CVE-2025-30152: Sylius PayPal Plugin has an Order Manipulation Vulnerability after PayPal Checkout

Published Mar 19, 2025
·
Updated

A discovered vulnerability allows users to modify their shopping cart after completing the PayPal Checkout process and payment authorization. If a user initiates a PayPal transaction from a product page or the cart page and then returns to the order summary page, they can still manipulate the cart contents before finalizing the order. As a result, the order amount in Sylius may be higher than the amount actually captured by PayPal, leading to a scenario where merchants deliver products or services without full payment.

Impact

- Users can exploit this flaw to receive products/services without paying the full amount. - Merchants may suffer financial losses due to underpaid orders. - Trust in the integrity of the payment process is compromised.

Patches

The issue is fixed in versions: 1.6.2, 1.7.2, 2.0.2 and above.

Workarounds

To resolve the problem in the end application without updating to the newest patches, there is a need to overwrite PayPalOrderCompleteProcessor with modified logic:

php <?php

declare(stricttypes=1);

namespace App\Processor;

use Sylius\Bundle\PayumBundle\Model\GatewayConfigInterface; use Sylius\Component\Core\Model\OrderInterface; use Sylius\Component\Core\Model\PaymentInterface; use Sylius\Component\Core\Model\PaymentMethodInterface; use Sylius\PayPalPlugin\Manager\PaymentStateManagerInterface;

final class PayPalOrderCompleteProcessor { public function construct(private readonly PaymentStateManagerInterface $paymentStateManager) { }

public function completePayPalOrder(OrderInterface $order): void { $payment = $order->getLastPayment(PaymentInterface::STATEPROCESSING); if ($payment === null) { return; }

/ @var PaymentMethodInterface $paymentMethod / $paymentMethod = $payment->getMethod(); / @var GatewayConfigInterface $gatewayConfig / $gatewayConfig = $paymentMethod->getGatewayConfig();

if ($gatewayConfig->getFactoryName() !== 'sylius.paypal') { return; }

try { $this->verify($payment); } catch (\Exception) { $this->paymentStateManager->cancel($payment);

return; }

$this->paymentStateManager->complete($payment); }

private function verify(PaymentInterface $payment): void { $totalAmount = $this->getTotalPaymentAmountFromPaypal($payment);

if ($payment->getOrder()->getTotal() !== $totalAmount) { throw new \Exception(); } }

private function getTotalPaymentAmountFromPaypal(PaymentInterface $payment): int { $details = $payment->getDetails();

return $details['paymentamount'] ?? 0; } }

IMPORTANT

For PayPalPlugin 2.x change: php $gatewayConfig->getFactoryName() !== 'sylius.paypal' to php $gatewayConfig->getFactoryName() !== SyliusPayPalExtension::PAYPALFACTORYNAME

Also there is a need to overwrite CompletePayPalOrderListener with modified logic:

php <?php

declare(stricttypes=1);

namespace App\EventListener\Workflow;

use App\Processor\PayPalOrderCompleteProcessor; use Sylius\Component\Core\Model\OrderInterface; use Symfony\Component\Workflow\Event\CompletedEvent; use Webmozart\Assert\Assert;

final class CompletePayPalOrderListener { public function construct(private readonly PayPalOrderCompleteProcessor $completeProcessor) { }

public function invoke(CompletedEvent $event): void { / @var OrderInterface $order / $order = $event->getSubject(); Assert::isInstanceOf($order, OrderInterface::class);

$this->completeProcessor->completePayPalOrder($order); } }

And to overwrite CaptureAction with modified logic (if you didn't have it already):

php <?php

declare(stricttypes=1);

namespace App\Payum\Action;

use Payum\Core\Action\ActionInterface; use Payum\Core\Exception\RequestNotSupportedException; use Payum\Core\Request\Capture; use Sylius\Component\Core\Model\PaymentInterface; use Sylius\Component\Core\Model\PaymentMethodInterface; use Sylius\PayPalPlugin\Api\CacheAuthorizeClientApiInterface; use Sylius\PayPalPlugin\Api\CreateOrderApiInterface; use Sylius\PayPalPlugin\Payum\Action\StatusAction; use Sylius\PayPalPlugin\Provider\UuidProviderInterface;

final class CaptureAction implements ActionInterface { public function construct( private CacheAuthorizeClientApiInterface $authorizeClientApi, private CreateOrderApiInterface $createOrderApi, private UuidProviderInterface $uuidProvider, ) { }

/ @param Capture $request / public function execute($request): void { RequestNotSupportedException::assertSupports($this, $request);

/ @var PaymentInterface $payment / $payment = $request->getModel(); / @var PaymentMethodInterface $paymentMethod / $paymentMethod = $payment->getMethod();

$token = $this->authorizeClientApi->authorize($paymentMethod);

$referenceId = $this->uuidProvider->provide(); $content = $this->createOrderApi->create($token, $payment, $referenceId);

if ($content['status'] === 'CREATED') { $payment->setDetails([ 'status' => StatusAction::STATUSCAPTURED, 'paypalorderid' => $content['id'], 'referenceid' => $referenceId, 'paymentamount' => $payment->getAmount(), ]); } }

public function supports($request): bool { return $request instanceof Capture && $request->getModel() instanceof PaymentInterface ; } }

After that, register services in the container when using PayPal 1.x:

yaml Sylius\PayPalPlugin\EventListener\Workflow\CompletePayPalOrderListener: class: App\EventListener\Workflow\CompletePayPalOrderListener public: true arguments: - '@Sylius\PayPalPlugin\Processor\PayPalOrderCompleteProcessor' tags: - { name: 'kernel.eventlistener', event: 'workflow.syliusordercheckout.completed.complete', priority: 100 } Sylius\PayPalPlugin\Processor\PayPalOrderCompleteProcessor: class: App\Processor\PayPalOrderCompleteProcessor public: true arguments: - '@Sylius\PayPalPlugin\Manager\PaymentStateManagerInterface'

Sylius\PayPalPlugin\Payum\Action\CaptureAction: class: App\Payum\Action\CaptureAction public: true arguments: - '@Sylius\PayPalPlugin\Api\CacheAuthorizeClientApiInterface' - '@Sylius\PayPalPlugin\Api\CreateOrderApiInterface' - '@Sylius\PayPalPlugin\Provider\UuidProviderInterface' tags: - { name: 'payum.action', factory: 'sylius.paypal', alias: 'payum.action.capture' }

or when using PayPal 2.x:

yaml syliuspaypal.listener.workflow.completepaypalorder: class: App\EventListener\Workflow\CompletePayPalOrderListener public: true arguments: - '@syliuspaypal.processor.paypalordercomplete' tags: - { name: 'kernel.eventlistener', event: 'workflow.syliusordercheckout.completed.complete', priority: 100 } syliuspaypal.processor.paypalordercomplete: class: App\Processor\PayPalOrderCompleteProcessor public: true arguments: - '@syliuspaypal.manager.paymentstate'

syliuspaypal.payum.action.capture: class: App\Payum\Action\CaptureAction public: true arguments: - '@syliuspaypal.api.cacheauthorizeclient' - '@syliuspaypal.api.createorder' - '@syliuspaypal.provider.uuid' tags: - { name: 'payum.action', factory: 'sylius.paypal', alias: 'payum.action.capture' }

For more information

If you have any questions or comments about this advisory: Open an issue in Sylius issues Email us at security@sylius.com

Other sources

The Syliud PayPal Plugin is the Sylius Core Team’s plugin for the PayPal Commerce Platform. Prior to 1.6.2, 1.7.2, and 2.0.2, a discovered vulnerability allows users to modify their shopping cart after completing the PayPal Checkout process and payment authorization. If a user initiates a PayPal transaction from a product page or the cart page and then returns to the order summary page, they can still manipulate the cart contents before finalizing the order. As a result, the order amount in Sylius may be higher than the amount actually captured by PayPal, leading to a scenario where merchants deliver products or services without full payment. The issue is fixed in versions: 1.6.2, 1.7.2, 2.0.2 and above.

— MITRE

Affected Software

4 affected componentsFixes available
Sylius PayPal Plugin<1.6.2, <1.7.2, <2.0.2
composer/sylius/paypal-plugin>=2.0.0<2.0.2
2.0.2
composer/sylius/paypal-plugin>=1.7.0<1.7.2
1.7.2
composer/sylius/paypal-plugin<1.6.2
1.6.2

Remediation

Recommended actions to resolve this vulnerability, in priority order.

  1. Upgrade

    Upgrade composer/sylius/paypal-plugin to a version that resolves this vulnerability.

    Fixed in 2.0.2
  2. Upgrade

    Upgrade composer/sylius/paypal-plugin to a version that resolves this vulnerability.

    Fixed in 1.7.2
  3. Upgrade

    Upgrade composer/sylius/paypal-plugin to a version that resolves this vulnerability.

    Fixed in 1.6.2
  4. Upgrade

    Upgrade to a fixed release to a version that resolves this vulnerability.

    Fixed in 1.6.2
  5. Upgrade

    Upgrade to a fixed release to a version that resolves this vulnerability.

    Fixed in 1.7.2
  6. Upgrade

    Upgrade to a fixed release to a version that resolves this vulnerability.

    Fixed in 2.0.2
  7. Configuration

    In the end application, register container services so that `App\EventListener\Workflow\CompletePayPalOrderListener`, `App\Payum\Action\CaptureAction`, and `App\Processor\PayPalOrderCompleteProcessor` are used instead of the plugin defaults; apply the modified logic shown (including the amount verification `if ($payment->getOrder()->getTotal() !== $totalAmount)`).

    PayPalPlugin (Sylius PayPal Plugin) - service container registration for PayPal 1.x service override / wiring = Overwrite `CompletePayPalOrderListener` with modified logic, and overwrite `CaptureAction` and `PayPalOrderCompleteProcessor` if needed (register the overridden services in the container for PayPal 1.x).

Event History

Mar 19, 2025
CVE Published
via MITRE·03:57 PM
Data Sourced
via MITRE·03:57 PM
DescriptionSeverityWeakness
Data Sourced
via NVD·04:15 PM
DescriptionSeverityWeakness
Advisory Published
via GitHub·04:46 PM
Mar 15, 57195
Event
via FIRST·08:49 AM

Frequently Asked Questions

1

What is the severity of CVE-2025-30152?

CVE-2025-30152 is classified as a critical vulnerability due to the potential for unauthorized modifications to a user's shopping cart after payment.

2

How do I fix CVE-2025-30152?

To fix CVE-2025-30152, upgrade the Sylius PayPal Plugin to version 1.6.2, 1.7.2, or 2.0.2 or later.

3

What software is affected by CVE-2025-30152?

CVE-2025-30152 affects the Sylius PayPal Plugin versions prior to 1.6.2, 1.7.2, and 2.0.2.

4

What impact does CVE-2025-30152 have on users?

CVE-2025-30152 allows users to potentially alter their shopping cart after completing a PayPal transaction, leading to unauthorized orders.

5

Is there a known exploit for CVE-2025-30152?

Yes, CVE-2025-30152 has been identified as allowing exploitation scenarios regarding cart modifications post-payment, posing security risks.

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203