Two Magento 2 security patches landed a day apart this week, and both are now in m2-meta-security-patches: Adobe’s StyleSmuggler fix — VULN-39341, APSB26-146, with the merchant announcement and downloads here — on the 7th, and September’s routine monthly isolated patch, 2026-09-001 / APSB26-138, on the 8th.

If you’re here for StyleSmuggler itself — what it is, how to hunt for compromise, how to recover — that’s not this post. I wrote a full incident-response runbook for it already, and it’s the one I’m keeping current as Sansec’s research evolves. This is the “it’s in the meta-package now” note, plus a read of what’s actually in the September isolated patch.

Getting it

Both are in 2026.09.08:

composer require samjuk/m2-meta-security-patches:">=2026.09.08"

Isolated patches stack, so 2026-09-001 will not apply unless 2026-08-001 is already on. If you’re behind, catch up in order — see the July and August posts if that catches you out.

Same caveat as every previous month: don’t rely on Dependabot/Renovate’s cooldown to deliver a security patch on time — treat the bump as a deliberate, triggered action. See the August post for why.

StyleSmuggler (VULN-39341 / APSB26-146)

Unauthenticated RCE, CVE-2026-75650, CVSS 10.0, actively exploited before Adobe shipped a fix. Found and documented by Sansec — their research post is the live source and still the thing to re-read before every hunt.

One patch file per base version — 2.4.6-p15, 2.4.7-p10, 2.4.8-p5, 2.4.9 are the ones this package carries (Adobe also ships 2.4.4-p18 and 2.4.5-p17, not covered here).

Patching alone does not clean an already-compromised node. If you were exposed before the 7th, my StyleSmuggler runbook covers hunting for the three implant builds Sansec found, and the reference doc carries the current indicators. Do that before you call the box clean.

September’s isolated patch (2026-09-001 / APSB26-138)

Adobe’s regular monthly cadence continues. Seven CVEs, one patch file per base version, and the same four CE lines as always:

CVEClassCVSS
CVE-2026-76200Stored XSS (CWE-79)9.3 Critical
CVE-2026-76201Stored XSS (CWE-79)9.3 Critical
CVE-2026-76202Incorrect authorization (CWE-863)8.2 High
CVE-2026-77109Incorrect authorization (CWE-863)8.6 High
CVE-2026-77110Path traversal (CWE-22)7.6 High
CVE-2026-77111Incorrect authorization (CWE-863)8.7 High
CVE-2026-77774Incorrect authorization (CWE-863)8.6 High

Adobe doesn’t publish a CVE-to-file mapping. The counts line up — seven CVEs, seven distinct code changes — but only two of them pair up unambiguously, so the rest are described below by what the diff actually does rather than by CVE.

What’s in it

PayPal Express quote binding. Magento\Paypal\Controller\Express\AbstractExpress::_initCheckout() stored whatever quote it was handed as the session’s PayPalQuoteId with no ownership check. The patch adds isQuoteAllowedForUser(): the quote must either already be the session’s own quote, or belong to the logged-in customer. Unauthenticated, no interaction, integrity impact — this is the one I’d rank first, and it’s the one worth smoke-testing after deploy.

GraphQL customer context across websites. Magento\CustomerGraphQl\Model\Context\AddUserInfoToContext treated any customer token as valid for any store. With customer accounts scoped per website, a token issued on website A resolved to a live customer context on website B. The patch resolves the effective store — from the Store header if present, otherwise the current store — and, when Share::isWebsiteScope() is on, requires the customer’s website to match. A token that fails now falls through to setUserId(0) rather than an authenticated context.

Instant Purchase address ownership. InstantPurchaseOptionLoadingFactory::create() loaded shipping and billing addresses by ID with no check that they belong to the customer making the purchase. Now both are compared against $customerId and a mismatch throws NoSuchEntityException('Address not found.') — hence the new en_US.csv string in module-customer.

Backup rollback ACL (likely CVE-2026-77111). Magento\Backup\Controller\Adminhtml\Index\Rollback had no ADMIN_RESOURCE, so it fell back to the default and any authenticated admin user could roll the database back over a live store. The patch pins it to Magento_Backup::rollback and drops the old isRollbackAllowed() config check, which was never an authorization control in the first place.

Export file deletion path traversal (likely CVE-2026-77110). Export\File\Delete concatenated the submitted filename straight onto the export path. Now the name goes through getRealPathSafety() and an isFile() existence check before anything is deleted. Admin-privileged, but arbitrary file deletion under var/ is more than enough to be worth patching.

Admin order create VAT XSS. Magento_Sales/order/create/scripts.js interpolated the raw VAT number into the “invalid VAT” message. underscore is now pulled into the define() block and the value goes through _.escape() before it reaches the message.

Escaper::escapeXssInUrl() single-pass decode. The method called html_entity_decode() once, then escaped — so a double-encoded payload survived one decode and came out live. The patch loops to a fixed point, capped at 10 iterations, and returns an empty string if it’s still decoding at the cap.

What to watch out for

  • PayPal Express is the regression risk. Any flow where the quote in play isn’t the session quote and the customer isn’t logged in now silently skips setPayPalQuoteId. Test guest express checkout from the mini-cart and the product page, and test the return-from-PayPal leg, before this goes near production on a PayPal-heavy store.
  • Headless and multi-website GraphQL. If your storefront sends no Store header, or the wrong one, against website-scoped customer accounts, tokens that used to work now resolve to an anonymous context. Nothing errors — carts and customer queries just come back logged out. Check your Store header handling first.
  • Magento_Sales/order/create/scripts.js picked up a new dependency. The define() argument list changed to function (jQuery, _, confirm, alert, ...). If a theme or module overrides or mixes into that file — and plenty do — the argument positions shift under it.
  • Custom admin roles lose backup rollback. The new Magento_Backup::rollback resource has to be granted explicitly. Any non-Administrator role that could roll back yesterday can’t today.
  • escapeXssInUrl() can now return empty. A URL that’s still decoding after 10 passes comes back as an empty string rather than mangled output. Legitimate content shouldn’t hit it, but if a URL renders blank after this patch, that’s where to look.
  • Instant Purchase with shared or company addresses. Any integration that hands Instant Purchase an address belonging to a different customer record now throws instead of proceeding.