SB20261105116 - Multiple vulnerabilities in Sylius
Published: November 5, 2026
Breakdown by Severity
- Low
- Medium
- High
- Critical
Description
This security bulletin contains information about 6 vulnerabilities.
1) Improper Handling of URL Encoding (Hex Encoding) (CVE-ID: N/A)
CWE-ID: CWE-177 - Improper Handling of URL Encoding (Hex Encoding)
CVSSv4: 6.9 [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]
The vulnerability allows remote attackers to reach the Sylius API even when an operator has disabled it through sylius_api.enabled. The entire API remains reachable subject to its normal authentication requirements, exposing anonymous shop operations and allowing credentialed access to protected endpoints. Unexpectedly exposed functionality includes customer registration, password reset requests, cart creation, and token endpoints, enabling input submission, email generation, and credential-stuffing attempts against an API the operator believed was unavailable. API-specific rate limits, WAF rules, or monitoring may also be absent because the operator considered that surface disabled.
The vulnerability exists due to inconsistent URL decoding between the API-disable subscriber and Symfony's routing machinery. The subscriber compares the raw, undecoded path returned by Request::getPathInfo() against the configured API prefix, while Symfony decodes the path before route matching. A remote attacker can bypass the disabled-API check without credentials by percent-encoding a character in the prefix, for example requesting /api/v%32/shop/orders instead of /api/v2/shop/orders. The encoded path does not contain the literal prefix checked by the subscriber, but subsequently decodes to a valid API route and is dispatched normally. Other percent-encoded forms of the prefix produce the same mismatch.
The configuration flag only causes KernelRequestEventSubscriber to reject matching requests; it does not unregister API Platform routes, remove resources or operations, or disable firewalls. The subscriber runs before routing, when route attributes are unavailable. The flag defaults to false, and Sylius-Standard enables it only in development, so an otherwise unmodified production installation can be affected even without an explicit decision to disable the API. This is a protection-mechanism failure, not an authentication bypass: firewall and access-control path matching decode the request normally, so administrator endpoints still require administrator credentials and customer-token-protected endpoints still require a token. The separately tracked Shop API ownership-filter issue is distinct from this disabled-API bypass.
2) Improper Handling of URL Encoding (Hex Encoding) (CVE-ID: N/A)
CWE-ID: CWE-177 - Improper Handling of URL Encoding (Hex Encoding)
CVSSv4: 8.6 [CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:N/SC:N/SI:N/SA:N]
The vulnerability allows a registered customer to bypass Sylius Shop API ownership, channel, and state filters to read, modify, and delete other customers' data. Exposed information includes all customers' addresses across channels and customer records containing email, first name, last name, default address, gender, birthday, phone number, and newsletter subscription status. An authenticated customer can also overwrite or delete another customer's address and overwrite another customer's profile. Only a valid customer account is required.
The vulnerability exists due to inconsistent decoding of request paths between Symfony and the Sylius application section resolver. Symfony applies rawurldecode() before route and firewall matching, while SyliusBundleCoreBundleSectionResolverUriBasedSectionProvider matches prefixes against the undecoded path. A remote attacker can authenticate with a valid customer account and percent-encode a character in the API prefix, requesting /api/v%32/shop/addresses instead of /api/v2/shop/addresses, to reach the same endpoint while causing section resolution to fall back to ShopSection rather than ShopApiSection. Every Shop API Doctrine query extension returns without applying its filters when the section is not ShopApiSection, causing authorization to fail open. These extensions are the only ownership enforcement on affected endpoints: is_granted('SYLIUS_SHOP_USER') checks the authenticated token rather than the requested record. The extensions apply to both collections and item operations, so the bypass also affects writes.
Encoding other characters in the prefix produces the same behavior, including /api/%76%32/shop/addresses, /%61pi/v2/shop/addresses, and /api/v2/%73hop/addresses. Affected operations include PUT and DELETE on /shop/addresses/{id} and PUT on /shop/customers/{id}. Stores with sylius_api.enabled set to false are also exposed because the API-disable check reads the raw path and can be bypassed by the same encoding, leaving the Shop API accessible without ownership filters. This does not enable account takeover through /shop/customers/{id}/password, which takes its subject from the authenticated token, or escalation to administrator endpoints, whose firewall and access-control rules decode the path and still require administrator credentials.
3) Weak Password Recovery Mechanism for Forgotten Password (CVE-ID: N/A)
CWE-ID: CWE-640 - Weak password recovery mechanism
CVSSv4: 8.3 [CVSS:4.0/AV:L/AC:L/AT:N/PR:N/UI:A/VC:H/VI:H/VA:N/SC:N/SI:N/SA:N]
The vulnerability allows an unauthenticated attacker to make a Sylius shop customer's password-reset e-mail link point to an attacker-controlled domain and capture the reset token when the customer clicks the link. The same URL-generation mechanism also affects links in user-registration, e-mail-verification and order-confirmation e-mails, as well as the logo and homepage links in the shared layout used by every Sylius e-mail.
The vulnerability exists due to ChannelUrlExtension::generateChannelUrl() falling back to UrlHelper::getAbsoluteUrl() when the resolved channel's optional hostname is empty, deriving the scheme and host from the incoming request without host validation. A remote attacker can submit the victim's e-mail address in an unauthenticated request to POST /api/v2/shop/customers/reset-password or the /{_locale}/forgotten-password form with a spoofed Host header to inject the destination domain into the reset link. Exposure requires the hostname-less channel to be resolved for that request and framework.trusted_hosts to be unset, as it is by default. A permissive trusted-host pattern such as .* also allows the attacker-supplied host. The optional channel hostname is empty by default on a single-channel installation unless an administrator supplies it.
A channel without a hostname cannot be matched by Host; SingleChannelContext instead selects it when exactly one channel exists. On a multi-channel store, a spoofed host matches no channel and no e-mail is sent, except that enabling kernel.debug permits channel selection through the _channel_code query parameter. X-Forwarded-Host influences URL generation only when framework.trusted_proxies is configured to trust x-forwarded-host; otherwise it is ignored. Trusted-proxy configuration does not itself validate hostnames, and trusting that header without host validation permits injection even with a correct Host header. Some affected implementations build the link directly in the e-mail template rather than through the extension, but use the same request-host fallback. Asynchronous Messenger delivery remains exposed because e-mails are rendered within the triggering request before being handed to the mailer. The administrator password-reset e-mail is not affected because it builds its link only from the channel hostname.
4) Missing Authorization (CVE-ID: N/A)
CWE-ID: CWE-862 - Missing Authorization
CVSSv4: 6.9 [CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:L/VI:N/VA:N/SC:N/SI:N/SA:N]
The vulnerability allows unauthenticated users to read unpublished Sylius product reviews awaiting moderation or already rejected, including their title, comment, rating, author's first name, reviewed product and dates. Sequential review identifiers allow enumeration of all pending and rejected reviews in a store. Visitors can also read their own and other users' reviews immediately after posting, before moderation. No write, integrity or privilege-escalation impact was identified.
The vulnerability exists due to moderation filtering being applied only to collection queries, while API Platform's default Doctrine item provider loads reviews by identifier without an equivalent accepted-status condition. A remote attacker can request /api/v2/shop/product-reviews/{id} using sequential numeric identifiers to retrieve reviews regardless of moderation status whenever the Shop API is reachable; no account, token or session is required. The collection query extensions, AcceptedExtension and AcceptedProductReviewsExtension, implement QueryCollectionExtensionInterface and are tagged api_platform.doctrine.orm.query_extension.collection, so their filtering does not apply to individual review requests.
Product reviews have a status of new, accepted or rejected, and only accepted reviews are intended to be publicly visible. The collection endpoint /shop/product-reviews correctly restricts results to accepted reviews, unlike the item endpoint. Reachability is a prerequisite: the advisory notes that, on installations also affected by a separate API-disabling bypass, a percent-encoded path could leave the Shop API reachable even with sylius_api.enabled set to false.
5) Time-of-check Time-of-use (TOCTOU) Race Condition (CVE-ID: N/A)
CWE-ID: CWE-367 - Time-of-check Time-of-use (TOCTOU) Race Condition
CVSSv4: 8.8 [CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:H/VA:L/SC:N/SI:N/SA:N]
The vulnerability allows unauthenticated remote attackers to bypass promotion and coupon usage limits in Sylius, redeeming limited-use discounts repeatedly and potentially causing direct financial loss. Both global promotion and coupon limits can be exceeded, including redemption of a single-use promotion or coupon multiple times. A single customer can also bypass a coupon's per-customer redemption limit by completing multiple orders concurrently.
The vulnerability exists due to a time-of-check to time-of-use race condition in order completion. Usage limits are checked only at the beginning of completion and are not checked again when usage counters are incremented. In AtomicOrderPromotionsUsageModifier, an entity is refreshed from the database and then optimistically locked using its own freshly retrieved version, so the lock cannot detect an intervening order completion. A remote attacker can prepare multiple carts using the same limited-use promotion or coupon and send PATCH requests to /api/v2/shop/orders/{token}/complete offset by a few milliseconds, allowing the requests to pass eligibility checks and complete with usage exceeding the limit. No authentication is required.
The affected limits are the global used counter on Promotion entities, the global used counter on PromotionCoupon entities, and the per-customer redemption count for PromotionCoupon entities. The optimistic lock does not detect orders completed between the initial eligibility check and the counter increment, leaving all three limits exposed to concurrent redemption.
6) Incorrect authorization (CVE-ID: N/A)
CWE-ID: CWE-863 - Incorrect Authorization
CVSSv4: 5.3 [CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N]
The vulnerability allows a Sylius shop customer, or a guest holding an order token, to bypass payment method restrictions for their own placed order and create a payment request using a method that is disabled or not assigned to the order's channel. The request is processed through that method's configured gateway, allowing payment routing through a gateway the merchant did not intend to offer on that channel, such as one intended for another market or taken out of service.
The vulnerability exists due to missing payment method eligibility validation on the AddPaymentRequest command. AddPaymentRequestHandler retrieves the caller-selected method using an unfiltered findOneBy lookup by code and creates a payment request without checking whether the method is enabled and assigned to the order's channel. A remote attacker can act as a shop customer or a guest holding the order token and submit an existing store payment method's code as paymentMethodCode to POST /api/v2/shop/orders/{tokenValue}/payment-requests for their own order.
The ChoosePaymentMethod and ChangePaymentMethod commands use the ChosenPaymentMethodEligibility constraint, which resolves eligible methods through sylius.resolver.payment_methods and rejects unsupported selections with HTTP 422; AddPaymentRequest lacks this constraint. Payment ownership is still verified, and the payment must belong to the order identified by the token. The issue is therefore a payment method restriction bypass on the caller's own order, not cross-customer access.
Remediation
Install update from vendor's website.
References
- https://github.com/Sylius/Sylius/security/advisories/GHSA-mw28-p745-4jrv
- https://github.com/Sylius/Sylius/security/advisories/GHSA-cqw6-3fwg-cfv4
- https://github.com/Sylius/Sylius/security/advisories/GHSA-v78h-66q4-h9px
- https://github.com/Sylius/Sylius/security/advisories/GHSA-5mpg-w6q2-2vrw
- https://github.com/Sylius/Sylius/security/advisories/GHSA-h76r-rr27-3gm4
- https://github.com/Sylius/Sylius/security/advisories/GHSA-ccgh-6w73-crf8