Skip to content

Prevent usernames from acting as permission wildcards - #27379

Open
dennisoelkers wants to merge 3 commits into
masterfrom
fix/username-wildcard-permission-injection
Open

dennisoelkers wants to merge 3 commits into
masterfrom
fix/username-wildcard-permission-injection

Conversation

@dennisoelkers

Copy link
Copy Markdown
Member

Description

Motivation and Context

Every non-service-account user implicitly receives self-service permissions built by string concatenation:

`users:edit:<username>`, `users:passwordchange:<username>`, ...

Those strings are parsed as Shiro wildcard permissions, where "" matches anything and "," separates alternatives. Usernames were only length checked, so a user named "" held users:edit:* and users:passwordchange:* over every other account, and a user named "admin,attacker" held them over "admin". The same concatenation is used when a grant target is turned into a Shiro permission, so the entity ID of a grant had the same problem.

Two ways in: a holder of users:create makes such a user and logs in as it, or an authentication service supplies the name, since provisioning copies the external username verbatim. PrivilegeEscalationGuard does not see these implicit permissions, so neither path is caught.

Fixed in two layers:

  • PermissionInstances#isSafe rejects identifiers that do not address a single instance. Permissions#userSelfEditPermissions grants nothing for such a username and DomainActionPermission#toShiroPermission returns a permission that implies nothing, so accounts already stored with such a name are harmless without a migration.
  • UsernameValidator rejects these names on save, which covers user creation, updates and authentication service provisioning alike.

Note this is a behaviour change for deployments that use an identifier containing "," or ":" as the username attribute, for example a full LDAP DN. Those accounts keep working but lose the implicit self-service permissions, and saving them fails until they are renamed.

How Has This Been Tested?

Screenshots (if appropriate):

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Refactoring (non-breaking change)
  • Breaking change (fix or feature that would cause existing functionality to change)

Checklist:

  • My code follows the code style of this project.
  • My change requires a change to the documentation.
  • I have requested a documentation update.
  • I have read the CONTRIBUTING document.
  • I have added tests to cover my changes.

dennisoelkers and others added 3 commits September 14, 2026 09:59
Every non-service-account user implicitly receives self-service
permissions built by string concatenation:

    users:edit:<username>, users:passwordchange:<username>, ...

Those strings are parsed as Shiro wildcard permissions, where "*" matches
anything and "," separates alternatives. Usernames were only length
checked, so a user named "*" held users:edit:* and
users:passwordchange:* over every other account, and a user named
"admin,attacker" held them over "admin". The same concatenation is used
when a grant target is turned into a Shiro permission, so the entity ID of
a grant had the same problem.

Two ways in: a holder of users:create makes such a user and logs in as
it, or an authentication service supplies the name, since provisioning
copies the external username verbatim. PrivilegeEscalationGuard does not
see these implicit permissions, so neither path is caught.

Fixed in two layers:

  - PermissionInstances#isSafe rejects identifiers that do not address a
    single instance. Permissions#userSelfEditPermissions grants nothing
    for such a username and DomainActionPermission#toShiroPermission
    returns a permission that implies nothing, so accounts already stored
    with such a name are harmless without a migration.
  - UsernameValidator rejects these names on save, which covers user
    creation, updates and authentication service provisioning alike.

Note this is a behaviour change for deployments that use an identifier
containing "," or ":" as the username attribute, for example a full LDAP
DN. Those accounts keep working but lose the implicit self-service
permissions, and saving them fails until they are renamed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant