{"id":"GHSA-6955-hrm5-c4qp","summary":"Sylius: Channel-based payment method restriction bypass on shop account orders API endpoint","details":"### Impact\nAn authorization bypass vulnerability exists in the shop account API. The `PATCH /api/v2/shop/account/orders/{tokenValue}/payments/{paymentId}` endpoint, used by an authenticated shop customer to change the payment method of an order that has been placed but not yet paid (state `STATE_NEW`), does not validate that the chosen payment method is enabled for the order's channel. The equivalent checkout endpoint (`PATCH /api/v2/shop/orders/{tokenValue}/payments/{paymentId}`) correctly rejects out-of-channel payment methods with `HTTP 422`; the account endpoint silently accepts them and returns `HTTP 200`.\n\nAn authenticated customer can therefore assign any globally enabled payment method to their own placed order, including methods that the store operator has explicitly excluded from that channel. \n\n### Patches\nThe issue is fixed in versions: 2.0.18, 2.1.15, 2.2.6 and above.\n\n### Workarounds\nIf users cannot bump Sylius right now, decorate the `Sylius\\Bundle\\ApiBundle\\Changer\\PaymentMethodChangerInterface` service in their applications. \n\n#### Step 1. Create the decorator\n\n`src/Decorator/ChannelCheckingPaymentMethodChanger.php`:\n\n```php\n\u003c?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Decorator;\n\nuse ApiPlatform\\Validator\\Exception\\ValidationException;\nuse Sylius\\Bundle\\ApiBundle\\Changer\\PaymentMethodChangerInterface;\nuse Sylius\\Component\\Core\\Model\\OrderInterface;\nuse Sylius\\Component\\Core\\Model\\PaymentMethodInterface;\nuse Sylius\\Component\\Core\\Repository\\PaymentMethodRepositoryInterface;\nuse Sylius\\Component\\Core\\Repository\\PaymentRepositoryInterface;\nuse Sylius\\Component\\Payment\\Resolver\\PaymentMethodsResolverInterface;\nuse Symfony\\Component\\Validator\\ConstraintViolation;\nuse Symfony\\Component\\Validator\\ConstraintViolationList;\nuse Symfony\\Contracts\\Translation\\TranslatorInterface;\n\nfinal readonly class ChannelCheckingPaymentMethodChanger implements PaymentMethodChangerInterface\n{\n    public function __construct(\n        private PaymentMethodChangerInterface $decorated,\n        private PaymentRepositoryInterface $paymentRepository,\n        private PaymentMethodRepositoryInterface $paymentMethodRepository,\n        private PaymentMethodsResolverInterface $paymentMethodsResolver,\n        private TranslatorInterface $translator,\n    ) {\n    }\n\n    public function changePaymentMethod(string $paymentMethodCode, mixed $paymentId, OrderInterface $order): OrderInterface\n    {\n        /** @var PaymentMethodInterface|null $paymentMethod */\n        $paymentMethod = $this-\u003epaymentMethodRepository-\u003efindOneBy(['code' =\u003e $paymentMethodCode]);\n        $payment = $this-\u003epaymentRepository-\u003efindOneByOrderId($paymentId, $order-\u003egetId());\n\n        if (\n            $paymentMethod !== null\n            && $payment !== null\n            && !in_array($paymentMethod, $this-\u003epaymentMethodsResolver-\u003egetSupportedMethods($payment), true)\n        ) {\n            $template = 'sylius.payment_method.not_available';\n            $parameters = ['%name%' =\u003e (string) $paymentMethod-\u003egetName()];\n\n            throw new ValidationException(new ConstraintViolationList([\n                new ConstraintViolation(\n                    message: $this-\u003etranslator-\u003etrans($template, $parameters, 'validators'),\n                    messageTemplate: $template,\n                    parameters: $parameters,\n                    root: $paymentMethodCode,\n                    propertyPath: '',\n                    invalidValue: $paymentMethodCode,\n                ),\n            ]));\n        }\n\n        return $this-\u003edecorated-\u003echangePaymentMethod($paymentMethodCode, $paymentId, $order);\n    }\n}\n```\n\n#### Step 2. Register the decorator\n\n`config/services.yaml` (append to the application's existing `services:` block):\n\n```yaml\nservices:\n    App\\Decorator\\ChannelCheckingPaymentMethodChanger:\n        decorates: sylius_api.changer.payment_method\n        arguments:\n            - '@.inner'\n            - '@sylius.repository.payment'\n            - '@sylius.repository.payment_method'\n            - '@sylius.resolver.payment_methods'\n            - '@translator'\n```\n\n`@.inner` references the original `PaymentMethodChangerInterface` implementation, so any future Sylius change to the changer keeps working through the decorator.\n\n#### Step 3. Clear the 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- Fredrik Dietrichson (@FredrikEV)\n\n### For more information\n\nIf there are 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- Send an email to [security@sylius.com](mailto:security@sylius.com)","aliases":["CVE-2026-53638"],"modified":"2026-07-09T21:26:41.702727Z","published":"2026-07-09T21:03:46Z","database_specific":{"severity":"MODERATE","github_reviewed":true,"github_reviewed_at":"2026-07-09T21:03:46Z","nvd_published_at":null,"cwe_ids":["CWE-863"]},"references":[{"type":"WEB","url":"https://github.com/Sylius/Sylius/security/advisories/GHSA-6955-hrm5-c4qp"},{"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.18"}]}],"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.16","v2.0.17","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":{"source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/07/GHSA-6955-hrm5-c4qp/GHSA-6955-hrm5-c4qp.json"}},{"package":{"name":"sylius/sylius","ecosystem":"Packagist","purl":"pkg:composer/sylius/sylius"},"ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"2.1.0"},{"fixed":"2.1.15"}]}],"versions":["v2.1.0","v2.1.1","v2.1.10","v2.1.11","v2.1.12","v2.1.13","v2.1.14","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":{"source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/07/GHSA-6955-hrm5-c4qp/GHSA-6955-hrm5-c4qp.json"}},{"package":{"name":"sylius/sylius","ecosystem":"Packagist","purl":"pkg:composer/sylius/sylius"},"ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"2.2.0"},{"fixed":"2.2.6"}]}],"versions":["v2.2.0","v2.2.1","v2.2.2","v2.2.3","v2.2.4","v2.2.5"],"database_specific":{"source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/07/GHSA-6955-hrm5-c4qp/GHSA-6955-hrm5-c4qp.json"}}],"schema_version":"1.9.0","severity":[{"type":"CVSS_V3","score":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N"}]}