{"id":"GHSA-wjmg-4cq5-m8hg","summary":"Sylius is Missing Authorization in API v2 Add Item Endpoint","details":"### Impact\nThe `POST /api/v2/shop/orders/{tokenValue}/items` endpoint does not verify cart ownership. An unauthenticated attacker can add items to other registered customers' carts by knowing the cart `tokenValue`.\n\n```\nPOST /api/v2/shop/orders/{tokenValue}/items\n```\n\nOther mutation endpoints (PUT, PATCH, DELETE) are **not affected**. API Platform loads the Order entity through the state provider for these operations, which triggers `VisitorBasedExtension` and returns 404 for unauthorized users.\n\nAn attacker who obtains a cart `tokenValue` can add arbitrary items to another customer's cart. The endpoint returns the full cart representation in the response (HTTP 201), potentially leaking:\n\n- Customer email address\n- Cart contents (products, quantities, prices)\n- Address data (billing and shipping if set)\n- Payment and shipment IDs\n- Order totals and tax breakdown\n- Checkout state\n\n### Patches\nThe issue is fixed in versions: 2.0.16, 2.1.12, 2.2.3, and above.\n\n### Workarounds\nAdd an ownership check in `AddItemToCartHandler` by injecting `UserContextInterface` and verifying the current user matches the cart owner before adding items.\n\n#### Step 1. Patch the handler\n\nCreate new  `src/CommandHandler/Cart/AddItemToCartHandler.php`:\n\n```php\n\u003c?php\n\ndeclare(strict_types=1);\n\nnamespace App\\CommandHandler\\Cart;\n\nuse Sylius\\Bundle\\ApiBundle\\Command\\Cart\\AddItemToCart;\nuse Sylius\\Bundle\\ApiBundle\\Context\\UserContextInterface;\nuse Sylius\\Component\\Core\\Factory\\CartItemFactoryInterface;\nuse Sylius\\Component\\Core\\Model\\OrderInterface;\nuse Sylius\\Component\\Core\\Model\\OrderItemInterface;\nuse Sylius\\Component\\Core\\Model\\ProductVariantInterface;\nuse Sylius\\Component\\Core\\Model\\ShopUserInterface;\nuse Sylius\\Component\\Core\\Repository\\OrderRepositoryInterface;\nuse Sylius\\Component\\Core\\Repository\\ProductVariantRepositoryInterface;\nuse Sylius\\Component\\Order\\Modifier\\OrderItemQuantityModifierInterface;\nuse Sylius\\Component\\Order\\Modifier\\OrderModifierInterface;\nuse Symfony\\Component\\HttpKernel\\Exception\\NotFoundHttpException;\nuse Symfony\\Component\\Messenger\\Attribute\\AsMessageHandler;\n\n#[AsMessageHandler]\nfinal readonly class AddItemToCartHandler\n{\n    public function __construct(\n        private OrderRepositoryInterface $orderRepository,\n        private ProductVariantRepositoryInterface $productVariantRepository,\n        private OrderModifierInterface $orderModifier,\n        private CartItemFactoryInterface $cartItemFactory,\n        private OrderItemQuantityModifierInterface $orderItemQuantityModifier,\n        private UserContextInterface $userContext,\n    ) {\n    }\n\n    public function __invoke(AddItemToCart $addItemToCart): OrderInterface\n    {\n        /** @var ProductVariantInterface|null $productVariant */\n        $productVariant = $this-\u003eproductVariantRepository-\u003efindOneBy(['code' =\u003e $addItemToCart-\u003eproductVariantCode]);\n\n        if ($productVariant === null) {\n            throw new \\InvalidArgumentException('Product variant with given code has not been found.');\n        }\n\n        /** @var OrderInterface|null $cart */\n        $cart = $this-\u003eorderRepository-\u003efindCartByTokenValue($addItemToCart-\u003eorderTokenValue);\n\n        if ($cart === null) {\n            throw new \\InvalidArgumentException('Cart with given token has not been found.');\n        }\n\n        $this-\u003eassertCartAccessible($cart);\n\n        /** @var OrderItemInterface $cartItem */\n        $cartItem = $this-\u003ecartItemFactory-\u003ecreateNew();\n        $cartItem-\u003esetVariant($productVariant);\n\n        $this-\u003eorderItemQuantityModifier-\u003emodify($cartItem, $addItemToCart-\u003equantity);\n        $this-\u003eorderModifier-\u003eaddToOrder($cart, $cartItem);\n\n        return $cart;\n    }\n\n    private function assertCartAccessible(OrderInterface $cart): void\n    {\n        if ($cart-\u003eisCreatedByGuest()) {\n            return;\n        }\n\n        $cartCustomer = $cart-\u003egetCustomer();\n\n        if (null === $cartCustomer || null === $cartCustomer-\u003egetUser()) {\n            return;\n        }\n\n        $currentUser = $this-\u003euserContext-\u003egetUser();\n\n        if (\n            $currentUser instanceof ShopUserInterface\n            && $currentUser-\u003egetCustomer()?-\u003egetId() === $cartCustomer-\u003egetId()\n        ) {\n            return;\n        }\n\n        throw new NotFoundHttpException('Cart not found.');\n    }\n}\n```\n\n#### Step 2. Override the service\n\n```diff\n# config/services.yaml\n\nservices:\n    App\\:\n        resource: '../src/*'\n-       exclude: '../src/{Entity,Kernel.php}'                                                                         \n+       exclude: '../src/{Entity,Kernel.php,CommandHandler}'\n\n    sylius_api.command_handler.cart.add_item_to_cart:\n        class: App\\CommandHandler\\Cart\\AddItemToCartHandler\n        arguments:\n            $orderRepository: '@sylius.repository.order'\n            $productVariantRepository: '@sylius.repository.product_variant'\n            $orderModifier: '@sylius.modifier.order'\n            $cartItemFactory: '@sylius.factory.order_item'\n            $orderItemQuantityModifier: '@sylius.modifier.order_item_quantity'\n            $userContext: '@Sylius\\Bundle\\ApiBundle\\Context\\UserContextInterface'\n        tags:\n            - { name: messenger.message_handler, bus: sylius.command_bus }\n```\n\n#### Step 3. Clear cache\n\n```bash\nbin/console cache:clear\n```\n\n### Reporters\n\nWe would like to extend our gratitude to the following individuals for their detailed reporting and responsible disclosure of this vulnerability:\n- @rokorolov\n\n### For more information\nIf you have any questions or comments about this advisory:\n\n- Open an issue in [Sylius issues](https://github.com/Sylius/Sylius/issues?q=sort%3Aupdated-desc+is%3Aissue+is%3Aopen)\n- Email us at [security@sylius.com](mailto:security@sylius.com)","aliases":["CVE-2026-31821"],"modified":"2026-03-13T05:56:20.944014Z","published":"2026-03-11T00:12:54Z","database_specific":{"cwe_ids":["CWE-862"],"severity":"MODERATE","github_reviewed":true,"github_reviewed_at":"2026-03-11T00:12:54Z","nvd_published_at":"2026-03-10T22:16:19Z"},"references":[{"type":"WEB","url":"https://github.com/Sylius/Sylius/security/advisories/GHSA-wjmg-4cq5-m8hg"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-31821"},{"type":"PACKAGE","url":"https://github.com/Sylius/Sylius"}],"affected":[{"package":{"name":"sylius/sylius","ecosystem":"Packagist","purl":"pkg:composer/sylius/sylius"},"ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"2.0.0"},{"fixed":"2.0.16"}]}],"versions":["v2.0.0","v2.0.1","v2.0.10","v2.0.11","v2.0.12","v2.0.13","v2.0.14","v2.0.15","v2.0.2","v2.0.3","v2.0.4","v2.0.5","v2.0.6","v2.0.7","v2.0.8","v2.0.9"],"database_specific":{"last_known_affected_version_range":"\u003c= 2.0.15","source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/03/GHSA-wjmg-4cq5-m8hg/GHSA-wjmg-4cq5-m8hg.json"}},{"package":{"name":"sylius/sylius","ecosystem":"Packagist","purl":"pkg:composer/sylius/sylius"},"ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"2.1.0"},{"fixed":"2.1.12"}]}],"versions":["v2.1.0","v2.1.1","v2.1.10","v2.1.11","v2.1.2","v2.1.3","v2.1.4","v2.1.5","v2.1.6","v2.1.7","v2.1.8","v2.1.9"],"database_specific":{"last_known_affected_version_range":"\u003c= 2.1.11","source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/03/GHSA-wjmg-4cq5-m8hg/GHSA-wjmg-4cq5-m8hg.json"}},{"package":{"name":"sylius/sylius","ecosystem":"Packagist","purl":"pkg:composer/sylius/sylius"},"ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"2.2.0"},{"fixed":"2.2.3"}]}],"versions":["v2.2.0","v2.2.1","v2.2.2"],"database_specific":{"last_known_affected_version_range":"\u003c= 2.2.2","source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/03/GHSA-wjmg-4cq5-m8hg/GHSA-wjmg-4cq5-m8hg.json"}}],"schema_version":"1.9.0","severity":[{"type":"CVSS_V4","score":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:L/VI:L/VA:N/SC:N/SI:N/SA:N"}]}