Skip to main content

Shopware Store API CVE-2026-48016

MEDIUM
Authentication Bypass by Spoofing (CWE-290)
2026-06-04 https://github.com/shopware/shopware GHSA-9v5m-39wh-5chq
4.3
CVSS 3.1 · GitHub Advisory
Share

Severity by source

GitHub Advisory PRIMARY
4.3 MEDIUM
AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N

Primary rating from GitHub Advisory · only source for this CVE.

CVSS VectorGitHub Advisory

CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
Low
User Interaction
None
Scope
Unchanged
Confidentiality
None
Integrity
Low
Availability
None

Lifecycle Timeline

2
Source Code Evidence Fetched
Jun 04, 2026 - 20:03 vuln.today
Analysis Generated
Jun 04, 2026 - 20:03 vuln.today

DescriptionGitHub Advisory

Summary

The Shopware Store API endpoint /store-api/handle-payment contains an object-level authorization flaw that allows a low-privileged external user with a normal customer or guest context to trigger the payment flow for another user’s order by supplying a foreign orderId. The affected functionality is the Store API payment initiation and retry flow. The root cause is that the endpoint forwards the user-controlled orderId into the payment processing logic without verifying that the caller owns the referenced order or has passed the required guest-order authentication. As a result, payment attempts for foreign orders are accepted by the server, which can compromise the integrity of order and payment workflows.

Description

Shopware exposes /store-api/handle-payment to initiate or retry the payment flow for an already created order. Under the normal order access model, customers should only be able to view or act on their own orders, and guest users should only be able to access guest orders after completing additional verification such as deepLinkCode, email address, and postal code. The Store API /store-api/order route follows this model: authenticated customers only see their own orders, and guest users are denied access unless guest-order authentication is performed. However, /store-api/handle-payment does not follow the same protection model. It only checks whether the supplied orderId exists and then directly forwards it into the payment processing flow. As a result, an attacker who cannot read orders through the intended protected route can still trigger the payment retry or payment initiation logic for another customer’s order as long as they know a valid foreign order ID. Although orderId is a UUID-based identifier and is not trivially guessable, it is used throughout storefront order flows such as checkout finish, account order pages, payment change flows, and download links. It is therefore a business object identifier, not a secret bearer token. The server must not treat knowledge of a valid orderId as sufficient authorization and must instead verify that the caller is entitled to act on the referenced order. This is a backend authorization flaw caused by missing ownership validation on a sensitive order action.

Expected Behavior

/store-api/handle-payment should only be available when the caller is the legitimate owner of the referenced order or, in the case of a guest order, when the required guest-order authentication has been completed. Before processing a supplied orderId, the server should verify that the current SalesChannelContext belongs to the customer associated with that order, or that the caller has successfully passed the expected guest-order verification flow. At a minimum, it should follow the same object-level authorization model used by the protected /store-api/order route.

Root Cause

The vulnerable endpoint accepts orderId, checks only that the order exists and has a currency, and then forwards it into the payment processor without any ownership validation.

php
#[Route(path: '/store-api/handle-payment', name: 'store-api.payment.handle', methods: ['GET', 'POST'])]
public function load(Request $request, SalesChannelContext $context): HandlePaymentMethodRouteResponse
{
    $data = [...$request->query->all(), ...$request->request->all()];
    $this->dataValidator->validate($data, $this->createDataValidation());
    /** @var array{orderId: string, finishUrl?: string, errorUrl?: string} $data */
    $orderCurrencyId = $this->getCurrencyFromOrder($data['orderId'], $context->getContext());

    if ($context->getCurrencyId() !== $orderCurrencyId) {
        $context = $this->contextService->get(
            new SalesChannelContextServiceParameters(
                $context->getSalesChannelId(),
                $context->getToken(),
                $context->getLanguageId(),
                $orderCurrencyId,
            )
        );
    }

    $response = $this->paymentProcessor->pay(
        $data['orderId'],
        $request,
        $context,
        $data['finishUrl'] ?? null,
        $data['errorUrl'] ?? null,
    );

    return new HandlePaymentMethodRouteResponse($response);
}

File: src/Core/Checkout/Payment/SalesChannel/HandlePaymentMethodRoute.php

The internal payment processing path similarly uses the supplied orderId to find the current transaction without checking whether the current caller owns the order.

php
public function pay(
    string $orderId,
    Request $request,
    SalesChannelContext $salesChannelContext,
    ?string $finishUrl = null,
    ?string $errorUrl = null,
): ?RedirectResponse {
    $transaction = $this->getCurrentOrderTransaction($orderId, $salesChannelContext->getContext());
    if (!$transaction) {
        return null;
    }

    $response = $paymentHandler->pay($request, $transactionStruct, $salesChannelContext->getContext(), $validationStruct);

    return $response;
}

private function getCurrentOrderTransaction(string $orderId, Context $context): ?OrderTransactionEntity
{
    $criteria = (new Criteria())
        ->addFilter(new EqualsFilter('stateId', $this->initialStateIdLoader->get(OrderTransactionStates::STATE_MACHINE)))
        ->addFilter(new EqualsFilter('orderId', $orderId))
        ->addSorting(new FieldSorting('createdAt', FieldSorting::DESCENDING))
        ->setLimit(1);

    $transaction = $this->orderTransactionRepository->search($criteria, $context)->getEntities()->first();

    if (!$transaction) {
        $criteria->resetFilters();
        $criteria->addFilter(new EqualsFilter('orderId', $orderId));

        if ($this->orderTransactionRepository->searchIds($criteria, $context)->firstId()) {
            return null;
        }

        throw PaymentException::invalidOrder($orderId);
    }

    return $transaction;
}

File: src/Core/Checkout/Payment/PaymentProcessor.php

By contrast, the official order retrieval route explicitly enforces current-context order ownership.

php
if ($context->getCustomer()) {
    $criteria->addFilter(new EqualsFilter('order.orderCustomer.customerId', $context->getCustomerId()));
} elseif ($deepLinkFilter === null) {
    throw OrderException::customerNotLoggedIn();
}

if ($deepLinkFilter !== null && !$context->getCustomer()) {
    $order = $orders->first();

    if ($order === null) {
        throw OrderException::guestNotAuthenticated();
    }

    $this->guestAuthenticator->validate($order, $request);
}

File: src/Core/Checkout/Order/SalesChannel/OrderRoute.php

The Store API schema also reflects that /store-api/order is designed for customer-owned or guest-authenticated order access, while /store-api/handle-payment only requires orderId.

json
{
  "summary": "Fetch a list of orders",
  "description": "List orders of a customer."
}

File: src/Core/Framework/Api/ApiDefinition/Generator/Schema/StoreApi/paths/order.json

json
{
  "summary": "Initiate a payment for an order",
  "required": ["orderId"]
}

File: src/Core/Framework/Api/ApiDefinition/Generator/Schema/StoreApi/paths/handle-payment.json

The expected model is that both order access and payment initiation are tied to order ownership or guest-order authentication. The implemented model instead trusts a caller-supplied orderId and allows a sensitive payment action on a foreign order.

Impact

The attacker only needs to be a normal remote Store API user and does not need to be an authenticated backend user. Even a guest context is sufficient. No administrator privileges, backend access, shell access, or other special internal conditions are required. In a realistic scenario, an external user can create a normal guest Store API context through the storefront or Store API and then submit a valid foreign order ID learned through another channel to /store-api/handle-payment in order to trigger the payment retry or payment initiation flow for another customer’s order. Here, orderId should not be treated as a secret authorization token. While it is not trivially guessable, it is used throughout storefront order-related flows such as checkout finish, account order detail pages, payment update routes, and download links as a business object identifier. Treating possession of a valid orderId as sufficient authorization breaks the expectation that only the legitimate order owner, or a properly authenticated guest-order user, may perform payment-related follow-up actions. In practice, this can lead to unauthorized payment attempts, external payment integration calls, customer confusion, and disruption of order processing integrity. The primary impact is on the integrity of order and payment workflows, with potential secondary operational or availability impact depending on the payment integration.

Patch Recommendation

Before processing a supplied orderId, /store-api/handle-payment should enforce the same object-level authorization model used by the order access routes. For authenticated customers, the server should verify that the order belongs to the current customer. For guest orders, it should require and validate the same guest-order authentication conditions used in the official order retrieval flow. In addition, the internal payment processor should not resolve a transaction solely by orderId; transaction lookup should be constrained to orders that are authorized for the current sales channel context and caller.

AnalysisAI

Unauthorized payment triggering in Shopware's /store-api/handle-payment endpoint allows any low-privileged Store API caller - including guest checkout contexts - to initiate or retry the payment flow for another customer's order by supplying a known foreign orderId. The flaw affects shopware/platform and shopware/core versions below 6.6.10.18 and versions 6.7.0.0 through 6.7.10.0, and is confirmed fixed in releases 6.6.10.18 and 6.7.10.1 per GitHub advisory GHSA-9v5m-39wh-5chq. No public exploit code or CISA KEV listing has been identified at time of analysis, and the CVSS score of 4.3 (Medium) reflects limited scope: integrity of order and payment workflows is the primary risk, with no direct confidentiality or availability impact.

Technical ContextAI

Shopware is a PHP-based open-source e-commerce platform whose Store API exposes headless commerce endpoints to storefront clients and integrations. The vulnerable endpoint, HandlePaymentMethodRoute::load() in src/Core/Checkout/Payment/SalesChannel/HandlePaymentMethodRoute.php, accepts a caller-supplied orderId parameter and performs only an existence and currency check before forwarding the ID directly into PaymentProcessor::pay(). The PaymentProcessor then queries orderTransactionRepository filtered solely by orderId, with no constraint linking the transaction to the caller's SalesChannelContext or customer identity. This stands in direct contrast to OrderRoute.php, which enforces ownership via order.orderCustomer.customerId equality for authenticated customers and requires a full deepLinkCode/email/postal-code validation flow for guest orders. The assigned CWE-290 (Authentication Bypass by Spoofing) captures the trust misplacement, though the root-cause pattern more precisely matches a Broken Object-Level Authorization (BOLA/IDOR) flaw - the server accepts a user-controlled object identifier as an implicit authorization token. Affected packages are composer/shopware/platform and composer/shopware/core, confirmed via GHSA CPE data.

RemediationAI

The vendor-released patch is available: upgrade shopware/platform and shopware/core to version 6.6.10.18 (for the 6.6.x track) or 6.7.10.1 (for the 6.7.x track) as documented in the security advisory at https://github.com/shopware/shopware/security/advisories/GHSA-9v5m-39wh-5chq. Composer-managed installations should run composer update shopware/platform shopware/core with appropriate version constraints and verify the installed version. If an immediate upgrade is not feasible, a compensating control is to place a web application firewall or reverse-proxy rule that requires the sw-context-token (or session token) to match the customer record associated with the submitted orderId before routing requests to /store-api/handle-payment; however, this requires custom middleware and introduces operational complexity. Alternatively, temporarily disabling the /store-api/handle-payment endpoint at the network or routing layer will prevent exploitation but will break payment retry flows for all customers, impacting checkout completion rates. Neither workaround fully substitutes for the vendor patch, which adds the required object-level authorization check at the application layer.

More in PHP

View all
CVE-2012-1823 CRITICAL POC
9.8 May 11

sapi/cgi/cgi_main.c in PHP before 5.3.12 and 5.4.x before 5.4.2, when configured as a CGI script (aka php-cgi), does not

CVE-2016-1555 CRITICAL POC
9.8 Apr 21

(1) boardData102.php, (2) boardData103.php, (3) boardDataJP.php, (4) boardDataNA.php, and (5) boardDataWW.php in Netgear

CVE-2024-11680 CRITICAL POC
9.8 Nov 26

ProjectSend versions prior to r1720 are affected by an improper authentication vulnerability. Rated critical severity (C

CVE-2025-49113 CRITICAL POC
9.9 Jun 02

Roundcube Webmail contains a critical PHP object deserialization vulnerability (CVE-2025-49113, CVSS 9.9) that allows au

CVE-2017-9841 CRITICAL POC
9.8 Jun 27

Util/PHP/eval-stdin.php in PHPUnit before 4.8.28 and 5.x before 5.6.3 allows remote attackers to execute arbitrary PHP c

CVE-2025-0108 HIGH POC
8.8 Feb 12

Palo Alto Networks PAN-OS management web interface contains an authentication bypass allowing unauthenticated attackers

CVE-2021-25298 HIGH POC
8.8 Feb 15

Nagios XI version xi-5.7.5 is affected by OS command injection. Rated high severity (CVSS 8.8), this vulnerability is re

CVE-2021-25296 HIGH POC
8.8 Feb 15

Nagios XI version xi-5.7.5 is affected by OS command injection. Rated high severity (CVSS 8.8), this vulnerability is re

CVE-2013-4983 CRITICAL POC
10.0 Sep 10

The get_referers function in /opt/ws/bin/sblistpack in Sophos Web Appliance before 3.7.9.1 and 3.8 before 3.8.1.1 allows

CVE-2023-6553 CRITICAL POC
9.8 Dec 15

The Backup Migration plugin for WordPress is vulnerable to Remote Code Execution in all versions up to, and including, 1

CVE-2024-46506 CRITICAL POC
10.0 May 13

NetAlertX (formerly PiAlert) versions 23.01.14 through 24.x before 24.10.12 allow unauthenticated command injection thro

CVE-2024-8353 CRITICAL POC
9.8 Sep 28

The GiveWP - Donation Plugin and Fundraising Platform plugin for WordPress is vulnerable to PHP Object Injection in all

Share

CVE-2026-48016 vulnerability details – vuln.today

This site uses cookies essential for authentication and security. No tracking or analytics cookies are used. Privacy Policy