CVE-2026-48016: Shopware Unauthorized Payment Trigger For Foreign Vulnerability

MODERATE
Advisory Identifier: GHSA-9v5m-39wh-5chq
CVSS 4.3
CWE-290
Published
Advisory Summary

CVE-2026-48016 is a MODERATE (CVSS 4.3) unauthorized payment trigger for foreign vulnerability (CWE-290: Authentication Bypass by Spoofing) affecting Shopware libraries in the Packagist ecosystem. The issue involves unauthorized payment trigger for foreign orders via /store-api/handle-payment. Remediation is available by upgrading affected packages to version 6.7.10.1, 6.6.10.18.

CVE-2026-48016 at a Glance

CVE Identifier CVE-2026-48016
GHSA Identifier GHSA-9v5m-39wh-5chq
Severity MODERATE
CVSS v3.1 Base Score 4.3
CWE Classification CWE-290: Authentication Bypass by Spoofing
Affected Product Shopware
Package Ecosystem Packagist
Published Date
Last Updated

Security Impact

CVSS: 4.3

The security impact metrics below are parsed directly from the CVSS v3.1 vector string (CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N).

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

How to Fix CVE-2026-48016

To remediate this vulnerability, upgrade all affected Shopware dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.

shopware/platform fixed: 6.7.10.1
Upgrade shopware/platform to 6.7.10.1
shopware/platform fixed: 6.6.10.18
Upgrade shopware/platform to 6.6.10.18
shopware/core fixed: 6.7.10.1
Upgrade shopware/core to 6.7.10.1
shopware/core fixed: 6.6.10.18
Upgrade shopware/core to 6.6.10.18
Verify Direct and Transitive Dependencies

Run the following command in your project directory to verify that all resolved dependencies use the patched release:

inspect dependencies for shopware/platform

How to Check if You Are Affected

To determine whether your application is affected by CVE-2026-48016, inspect your project dependencies for Shopware:

inspect dependencies for shopware/platform

Analyze the terminal output to locate any version of Shopware in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 6.7.10.1), your application is affected.

Note: Verify declared build manifests and deployed runtime container environments.

Technical Details

Vulnerability Mechanism & Technical Analysis

This vulnerability is classified under CWE-290: Authentication Bypass by Spoofing, where this attack-focused weakness is caused by incorrectly implemented authentication schemes that are subject to spoofing attacks. In Shopware, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.

Source Advisory Statement

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

CVE-2026-48016 Affected Shopware Versions

4 component(s)
Fixed Versions:
6.7.10.16.6.10.18
Product / Package Ecosystem Affected Versions Fixed Version
shopware/platform
Packagist
≥ 6.7.0.0
< 6.7.10.1
6.7.10.1
shopware/platform
Packagist
< 6.6.10.18
6.6.10.18
shopware/core
Packagist
≥ 6.7.0.0
< 6.7.10.1
6.7.10.1
shopware/core
Packagist
< 6.6.10.18
6.6.10.18

References

Frequently Asked Questions

What is CVE-2026-48016?
CVE-2026-48016 is a security vulnerability in Shopware involving Unauthorized Payment Trigger for Foreign Orders via /store-api/handle-payment under CWE-290: Authentication Bypass by Spoofing.
Which Shopware versions are affected?
Affected versions include releases prior to 6.7.10.1, 6.6.10.18 across affected packages: shopware/platform, shopware/core.
What version fixes CVE-2026-48016?
Upgrading to 6.7.10.1, 6.6.10.18 (or the latest patched release for your respective branch) resolves the vulnerability.
Is shopware/platform affected?
Yes, shopware/platform is affected in releases prior to 6.7.10.1, 6.6.10.18. Upgrade your dependency to 6.7.10.1, 6.6.10.18 or later.
Is shopware/core affected?
Yes, shopware/core is affected in releases prior to 6.7.10.1, 6.6.10.18. Upgrade your dependency to 6.7.10.1, 6.6.10.18 or later.
What is the CVSS score of CVE-2026-48016?
CVE-2026-48016 has a CVSS v3.1 base score of 4.3 (MODERATE) with vector string CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N.
What CWE is associated with CVE-2026-48016?
CVE-2026-48016 is classified under CWE-290: Authentication Bypass by Spoofing (This attack-focused weakness is caused by incorrectly implemented authentication schemes that are subject to spoofing attacks.).
How can I check Packagist dependencies for CVE-2026-48016?
Run the dependency tree command: 'inspect dependencies for shopware/platform'. This command lists direct and transitive dependencies in your build configuration so you can verify if a vulnerable version is resolved.
Machine-readable OSV JSON OSV v1.5 Schema
Normalized schema output
{
  "schema_version" : "1.4.0",
  "id" : "GHSA-9v5m-39wh-5chq",
  "modified" : "2026-06-04T19:33:54Z",
  "published" : "2026-06-04T19:33:54Z",
  "aliases" : [ "CVE-2026-48016" ],
  "summary" : "Shopware: Unauthorized Payment Trigger for Foreign Orders via /store-api/handle-payment",
  "details" : "## Summary\n\nThe 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.\n\n## Description\n\nShopware 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.\n\n### Expected Behavior\n\n`/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.\n\n### Root Cause\n\nThe 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.\n\n```php\n#[Route(path: '/store-api/handle-payment', name: 'store-api.payment.handle', methods: ['GET', 'POST'])]\npublic function load(Request $request, SalesChannelContext $context): HandlePaymentMethodRouteResponse\n{\n    $data = [...$request->query->all(), ...$request->request->all()];\n    $this->dataValidator->validate($data, $this->createDataValidation());\n    /** @var array{orderId: string, finishUrl?: string, errorUrl?: string} $data */\n    $orderCurrencyId = $this->getCurrencyFromOrder($data['orderId'], $context->getContext());\n\n    if ($context->getCurrencyId() !== $orderCurrencyId) {\n        $context = $this->contextService->get(\n            new SalesChannelContextServiceParameters(\n                $context->getSalesChannelId(),\n                $context->getToken(),\n                $context->getLanguageId(),\n                $orderCurrencyId,\n            )\n        );\n    }\n\n    $response = $this->paymentProcessor->pay(\n        $data['orderId'],\n        $request,\n        $context,\n        $data['finishUrl'] ?? null,\n        $data['errorUrl'] ?? null,\n    );\n\n    return new HandlePaymentMethodRouteResponse($response);\n}\n```\n\nFile: `src/Core/Checkout/Payment/SalesChannel/HandlePaymentMethodRoute.php`\n\nThe internal payment processing path similarly uses the supplied `orderId` to find the current transaction without checking whether the current caller owns the order.\n\n```php\npublic function pay(\n    string $orderId,\n    Request $request,\n    SalesChannelContext $salesChannelContext,\n    ?string $finishUrl = null,\n    ?string $errorUrl = null,\n): ?RedirectResponse {\n    $transaction = $this->getCurrentOrderTransaction($orderId, $salesChannelContext->getContext());\n    if (!$transaction) {\n        return null;\n    }\n\n    $response = $paymentHandler->pay($request, $transactionStruct, $salesChannelContext->getContext(), $validationStruct);\n\n    return $response;\n}\n\nprivate function getCurrentOrderTransaction(string $orderId, Context $context): ?OrderTransactionEntity\n{\n    $criteria = (new Criteria())\n        ->addFilter(new EqualsFilter('stateId', $this->initialStateIdLoader->get(OrderTransactionStates::STATE_MACHINE)))\n        ->addFilter(new EqualsFilter('orderId', $orderId))\n        ->addSorting(new FieldSorting('createdAt', FieldSorting::DESCENDING))\n        ->setLimit(1);\n\n    $transaction = $this->orderTransactionRepository->search($criteria, $context)->getEntities()->first();\n\n    if (!$transaction) {\n        $criteria->resetFilters();\n        $criteria->addFilter(new EqualsFilter('orderId', $orderId));\n\n        if ($this->orderTransactionRepository->searchIds($criteria, $context)->firstId()) {\n            return null;\n        }\n\n        throw PaymentException::invalidOrder($orderId);\n    }\n\n    return $transaction;\n}\n```\n\nFile: `src/Core/Checkout/Payment/PaymentProcessor.php`\n\nBy contrast, the official order retrieval route explicitly enforces current-context order ownership.\n\n```php\nif ($context->getCustomer()) {\n    $criteria->addFilter(new EqualsFilter('order.orderCustomer.customerId', $context->getCustomerId()));\n} elseif ($deepLinkFilter === null) {\n    throw OrderException::customerNotLoggedIn();\n}\n\nif ($deepLinkFilter !== null && !$context->getCustomer()) {\n    $order = $orders->first();\n\n    if ($order === null) {\n        throw OrderException::guestNotAuthenticated();\n    }\n\n    $this->guestAuthenticator->validate($order, $request);\n}\n```\n\nFile: `src/Core/Checkout/Order/SalesChannel/OrderRoute.php`\n\nThe 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`.\n\n```json\n{\n  \"summary\": \"Fetch a list of orders\",\n  \"description\": \"List orders of a customer.\"\n}\n```\n\nFile: `src/Core/Framework/Api/ApiDefinition/Generator/Schema/StoreApi/paths/order.json`\n\n```json\n{\n  \"summary\": \"Initiate a payment for an order\",\n  \"required\": [\"orderId\"]\n}\n```\n\nFile: `src/Core/Framework/Api/ApiDefinition/Generator/Schema/StoreApi/paths/handle-payment.json`\n\nThe 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.\n\n## Impact\n\nThe 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.\n\n## Patch Recommendation\n\nBefore 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.",
  "severity" : [ {
    "type" : "CVSS_V3",
    "score" : "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N"
  } ],
  "affected" : [ {
    "package" : {
      "ecosystem" : "Packagist",
      "name" : "shopware/platform"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "6.7.0.0"
      }, {
        "fixed" : "6.7.10.1"
      } ]
    } ]
  }, {
    "package" : {
      "ecosystem" : "Packagist",
      "name" : "shopware/platform"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "0"
      }, {
        "fixed" : "6.6.10.18"
      } ]
    } ]
  }, {
    "package" : {
      "ecosystem" : "Packagist",
      "name" : "shopware/core"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "6.7.0.0"
      }, {
        "fixed" : "6.7.10.1"
      } ]
    } ]
  }, {
    "package" : {
      "ecosystem" : "Packagist",
      "name" : "shopware/core"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "0"
      }, {
        "fixed" : "6.6.10.18"
      } ]
    } ]
  } ],
  "references" : [ {
    "type" : "WEB",
    "url" : "https://github.com/shopware/shopware/security/advisories/GHSA-9v5m-39wh-5chq"
  }, {
    "type" : "PACKAGE",
    "url" : "https://github.com/shopware/shopware"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/shopware/shopware/releases/tag/v6.6.10.18"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/shopware/shopware/releases/tag/v6.7.10.1"
  } ],
  "database_specific" : {
    "cwe_ids" : [ "CWE-290" ],
    "severity" : "MODERATE",
    "github_reviewed" : true,
    "github_reviewed_at" : "2026-06-04T19:33:54Z",
    "nvd_published_at" : null
  }
}