Skip to content
winfunc
Disclosure record · Sylius

Shop JWT identifier collision enables admin API takeover

Shop and admin firewalls accepted JWTs from one signing domain without audience or principal binding

SyliusDisclosedSource record

CVSS 3.1 base score

High
8.8/ 10

Vector: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H

Record

Project
Sylius
Severity
High8.8
CVE
None listed
Disclosed
Trace
3 steps

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

  1. Source · attacker-controlledsrc/Sylius/Bundle/ApiBundle/Resources/config/serialization/Customer.xml:24

    Customer.email

  2. 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" }
    
  3. 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());
    
  4. 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: ~
    
  5. 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. 1

    Authenticate as an ordinary shop customer.

  2. 2

    Set the customer's email to the target administrator's email.

  3. 3

    Log in through the shop token endpoint and obtain a valid shop JWT with the colliding identifier.

  4. 4

    Replay that JWT against an admin API operation.

  5. 5

    The admin firewall resolves the identifier as the administrator and authorizes the request.

Proof of concept

Reproduction5 stages
  1. 01

    Environment setup

    Run an affected Sylius API build in an isolated store with one ordinary customer and one enabled API administrator.

  2. 02

    Target configuration

    Ensure both shop and admin JWT firewalls use the affected shared trust configuration and the administrator has ROLE_API_ACCESS.

  3. 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.

  4. 04

    Expected response

    The vulnerable release returns administrator-only data instead of rejecting the shop token.

  5. 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.

Before and after−4+6
api_shop:  jwt: ~api_admin:  jwt: ~api_shop:  jwt:    audience: sylius-shopapi_admin:  jwt:    audience: sylius-admin
View original source record

Check the upstream record for the project's current remediation status.

Your codebase

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.