Shop JWT identifier collision enables admin API takeover
Shop and admin firewalls accepted JWTs from one signing domain without audience or principal binding
CVSS 3.1 base score
HighVector: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
Summary
Source
Customer.email
src/Sylius/Bundle/ApiBundle/Resources/config/serialization/Customer.xml:24
Sink
security.firewalls.api_admin
config/packages/security.yaml:58
An ordinary customer could change their shop email to collide with an API administrator's identifier, obtain a normal shop JWT, and replay it to the admin API. The admin firewall reloaded the identifier through the administrator repository and granted the victim administrator's API role.
Root cause. The shop and admin API firewalls trusted the same Lexik JWT signing configuration, while the token lacked a firewall audience or principal-class claim. A writable customer email became the shop username, allowing a cross-repository identifier collision.
Remediation evidence. Sylius confirmed the report, published GHSA-f6mx-qxjc-55xf with an explicit Winfunc Research credit, and shipped patched releases 1.12.25, 1.13.17, 1.14.20, 2.1.16, and 2.2.9.
Severity
- Attack vectorAV
- Network
- Attack complexityAC
- Low
- Privileges requiredPR
- Low
- User interactionUI
- None
- ScopeS
- Unchanged
- ConfidentialityC
- High
- IntegrityI
- High
- AvailabilityA
- High
Metric values as published in the disclosure vector. Meters show how far each value raises exposure.
Source-to-sink trace
- Source · attacker-controlledsrc/
Sylius/ Bundle/ ApiBundle/ Resources/ config/ serialization/ Customer.xml:24 Customer.email
- Step 01src/
Sylius/ Bundle/ ApiBundle/ Resources/ config/ api_platform/ resources/ shop/ Customer.xml:66 A shop customer updates only their own email to the known identifier of an enabled API administrator.
python PUT /api/v2/shop/customers/{own-id} { "email": "admin@example.test" } - Step 02src/
Sylius/ Bundle/ UserBundle/ EventListener/ ORM/ DefaultUsernameORMListener.php Normal persistence synchronizes the chosen customer email into the shop user's canonical username.
php $user->setUsername($customer->getEmail()); - Step 03config/
packages/ security.yaml:58 The admin firewall accepts the shop-issued signature and resolves the colliding identifier as the existing AdminUser.
python api_admin: provider: sylius_admin_user_provider jwt: ~ - Sinkconfig/
packages/ security.yaml:58 security.firewalls.api_admin
Impact
Reported impact
The collision crosses the customer/admin trust boundary and grants the administrator's API authority, enabling access to cross-customer commerce data and state-changing administrative operations exposed by the deployment.
Attack surface
Sylius installations exposing both shop and admin APIs with JWT authentication on affected releases.
Preconditions
The attacker needs an ordinary shop account whose email can be changed and the email address of an enabled administrator with API access. No administrator password, signing key, or victim token is needed.
Attack path
- 1
Authenticate as an ordinary shop customer.
- 2
Set the customer's email to the target administrator's email.
- 3
Log in through the shop token endpoint and obtain a valid shop JWT with the colliding identifier.
- 4
Replay that JWT against an admin API operation.
- 5
The admin firewall resolves the identifier as the administrator and authorizes the request.
Proof of concept
- 01
Environment setup
Run an affected Sylius API build in an isolated store with one ordinary customer and one enabled API administrator.
- 02
Target configuration
Ensure both shop and admin JWT firewalls use the affected shared trust configuration and the administrator has
ROLE_API_ACCESS. - 03
Exploit delivery
Update the customer's own email to the administrator identifier, obtain a fresh shop token, and send it as a bearer token to an admin collection such as
/api/v2/admin/shipments. - 04
Expected response
The vulnerable release returns administrator-only data instead of rejecting the shop token.
- 05
Outcome
Patched releases bind tokens to the intended security context, so a shop token cannot authenticate as an AdminUser even when identifiers collide.
Remediation
Guidance
Upgrade to a version listed as patched in GHSA-f6mx-qxjc-55xf. Use distinct audiences or signing domains for shop and admin tokens, validate principal class, and prevent cross-provider identity reinterpretation.
api_shop:jwt: ~api_admin:jwt: ~api_shop: jwt: audience: sylius-shopapi_admin: jwt: audience: sylius-admin
Check the upstream record for the project's current remediation status.
Investigate the paths that matter in your codebase.
Winfunc can trace relevant code paths, preserve supporting evidence, and prepare remediation suggestions for engineering review within an agreed scope.
