v vanemmerik.ai / SUPPLY-CHAIN
Supply Chain · Watch Thursday · 23 July 2026 End-of-day synthesis 4 watches · 21 items

From the watchtower — what crossed the wire today.

A four-times-a-day standing watch on the open-source supply chain. Each pass pulls newly disclosed CVEs, freshly catalogued KEV adds, and active attacks reported in the wild — then ranks them by severity for the day.

The story of the day — Two Auth.js advisories that can silently disable authentication anchor a day otherwise dominated by open redirects and memory-exhaustion bugs — React Router's four-advisory redirect-hardening batch, a paired pypdf infinite-loop fix, and a fresh PHPSpreadsheet SSRF bypass — with nothing yet confirmed under active attack.

Two critical Auth.js disclosures anchor the day — a fail-open config bug and a homoglyph email bypass that can silently authenticate anyone or misroute a victim's magic link, both still without a patched release.

Everything else that landed today is the quieter, high-volume half of the ledger: React Router closed out a four-advisory batch tightening open-redirect and XSS handling around `<Link>`/`useNavigate()`; PHPSpreadsheet picked up a second SSRF-whitelist bypass in its WEBSERVICE() formula plus two memory-exhaustion bugs in its file-sniffing readers; and pypdf shipped a matched pair of infinite-loop fixes for unterminated inline images, alongside singles in PostCSS (arbitrary file read via sourceMappingURL), find-my-way (an HTTP/2 prototype-pollution crash), ImageMagick, and c3p0. None of it is under active attack — no new CISA KEV entries landed today, and the only threat-actor signal tonight was an unrelated msaRAT malware writeup routing C2 through the browser.

→ Operational priority for the night patch or work around the two Auth.js criticals first — no patched version exists yet for either, so auditing `!!auth` checks and normalizing emails through NFKC before validation are the only fix until next-auth ships one.

18:00 ET · First Watch

find-my-way: DDoS with HTTP2

find-my-way (Fastify's router) indexes its route tree by `req.method`, and since `this.trees` is a plain object, an HTTP/2 request with a method like `constructor` or `__proto__` resolves an inherited Object property instead of undefined, crashing the process when the router treats it as a route node. Any Fastify-based service terminating HTTP/2 directly is exposed to a one-request crash. Upgrade to find-my-way 9.7.0, or validate the HTTP method against a known-good set before it reaches the router.

pypdf: Possible infinite loop for not terminated inline images (ASCII85 and ASCIIHex filter)

pypdf's inline-image parser doesn't bound the ASCII85/ASCIIHex filter scan, so a PDF with an unterminated inline image sends text extraction into an infinite loop — a companion bug to the identical-shape issue below for other inline-image encodings. Fixed in pypdf 6.14.2; bundle with the sibling fix and today's other pypdf DoS advisories.

pypdf: Possible infinite loop for not terminated inline images

Same infinite-loop shape as the ASCII85/ASCIIHex bug above, but in the general inline-image terminator scan — an unterminated inline image in a crafted PDF hangs any text-extraction pipeline. Fixed in pypdf 6.14.1; treat any pypdf < 6.14.2 deployment processing untrusted PDFs as due for an upgrade, not a one-off patch.

c3p0 can, in combination with other libraries, compose to a "sink" for deserialization gadgets

c3p0's pre-0.14.0 `DataSource`/`ConnectionPoolDataSource` implementations expose a `getConnection()` that Java's JavaBean introspection treats as a harmless property getter, so composing c3p0 with a gadget carrier like Apache commons-beanutils' comparator-over-collection lets a deserialization attack trigger a real JDBC connection attempt through a vulnerable driver. It's a supply-chain-composition bug — c3p0 just supplies one essential ingredient of a well-known gadget chain. Upgrade to c3p0 0.14.0+, which excludes `connection`/`pooledConnection` from introspected properties.

React Router: Open redirect via backslash in <Link> and useNavigate (CVE-2025-68470 bypass)

React Router's redirect-scheme fix for CVE-2025-68470 didn't fully close the door: a backslash-prefixed path passed to `<Link>` or `useNavigate()` can still be interpreted as protocol-relative and navigate the browser off-site. First of four React Router advisories published together today, all in the open-redirect/XSS family. Validate that navigation targets don't start with `\` or `//` before passing them to the router until patched versions ship.

React Router: Open redirect leading to XSS

A second React Router open-redirect bug: an attacker-controlled path routed through `<Link>`/`useNavigate()` can both redirect off-site and inject script via the redirect target, not just leak the user off the app (CVSS 6.9). Same batch as the backslash bypass above — treat any user-supplied navigation target as untrusted until react-router-dom 6.30.5+/react-router 7.12.1+ ship.

React Router: RSCErrorHandler Missing Protocol Validation (XSS)

Third in the batch: React Router's unstable RSC error-handling path doesn't validate the protocol on redirect targets, so an attacker-controlled redirect from an untrusted source can carry an XSS payload — only reachable if you're on the unstable RSC APIs. Same root shape as the two open-redirect bugs above. If you've opted into RSC, avoid trusting redirect targets from untrusted sources until patched.

React Router: Arbitrary Constructor Injection via deserializeErrors() in React Router SSR Hydration

Fourth React Router advisory: `deserializeErrors()` in the SSR hydration path can be coerced into invoking an arbitrary constructor if application code lets attacker input overwrite parts of an SSR-caught error object — narrow (Framework/Data Mode manual hydration only, not Declarative Mode) but rounds out today's four-advisory React Router batch. Check whether your SSR error-boundary code echoes untrusted fields back into the caught error.

ImageMagick: Information Disclosure in MNG decoder because allocated memory is left unchanged

ImageMagick's MNG decoder (as shipped via Magick.NET) leaves part of the allocated pixel buffer untouched when decoding certain MNG frames, so the output image can carry leftover heap bytes from prior allocations — a low-severity info leak (CVSS 5.3), not code execution. Patch lands in Magick.NET 14.15.0; treat decoded pixel data from untrusted MNG uploads as potentially containing stale memory until then.

Ruby json: JSON generator heap buffer overflow when streaming to an IO

Ruby's bundled `json` gem writes past its internal generator buffer when `JSON.dump(obj, io)` streams an attacker-controlled string landing within a couple bytes of the 16KB IO-buffer boundary, corrupting heap memory in a way the advisory demonstrates as a reliable crash. Only the IO-streaming path (`JSON.dump(obj, io)` / `State#generate(obj, io)`) is affected — the everyday `JSON.dump(obj)` without an IO argument is fine. No patched version yet; audit any code that serializes untrusted strings directly to an IO stream.

New msaRAT malware uses Chrome, Edge browsers to route C2 traffic

The Chaos ransomware gang's new msaRAT backdoor routes its command-and-control traffic through the victim's own Chrome or Edge process, so the C2 channel inherits the browser's legitimate TLS fingerprint and network egress rules instead of standing out as a raw socket. Not a supply-chain compromise itself, but the same evasion logic supply-chain implants increasingly borrow — egress monitoring that trusts "it's just the browser" is the gap this exploits. Worth a line in EDR/network detection rules that flag browser processes making C2-shaped connection patterns, not just unusual binaries.

12:00 ET · Forenoon Watch

Auth.js: Configuration errors can cause existence-based auth checks to fail open

When an Auth.js v5 provider is misconfigured (a Keycloak provider missing its issuer/authorization endpoint, an unset AUTH_SECRET), the auth() wrapper returns a truthy error object instead of null, so the exact `!!auth` pattern shown in Auth.js's own protecting-resources guide authenticates every visitor, including unauthenticated ones. It's the worst shape a config bug can take in an auth library: a silent deploy-time typo turns off authentication for the whole app with no error at the call site. Search middleware and route handlers for bare `!!auth` / `if (req.auth)` checks and switch to `!!auth?.user`; no patched version number has been published yet, only `next-auth@beta`.

Auth.js: Email normalizer validates the address before Unicode normalization, allowing a homoglyph @ bypass

Auth.js's default email-provider normalizer checks for a single `@` before Unicode-normalizing the address, so a character that isn't ASCII `@` but collapses to one under NFKC survives validation and is then read as a second separator by a downstream Unicode-aware mail sender, misrouting the magic-link email to an attacker-chosen mailbox. No victim interaction needed — the attacker just requests the link. Companion disclosure to today's other three Auth.js advisories, and like them the fix is pending an exact version; supply a custom `normalizeIdentifier` that calls `.normalize('NFKC')` before validating until then.

Auth.js: getToken() throws an uncaught exception on malformed Bearer authorization headers

getToken() URL-decodes a Bearer header before validating it, so a single unauthenticated request with malformed percent-encoding throws instead of returning null — an unhandled exception in whatever route handler or middleware called it directly. Availability-only impact, but it's a one-request DoS against any app that calls getToken() outside a try/catch. Wrap getToken() calls in try/catch until the fix ships; exact patched version is still pending.

PHPSpreadsheet: SSRF bypass via HTTP redirect in WEBSERVICE() domain whitelist

The WEBSERVICE() formula's domain whitelist, added in 5.4.0 to fix an earlier SSRF, only validates the initial URL's hostname — file_get_contents() then follows up to 20 redirects by default with no re-check, so a whitelisted domain that issues a 302 is a clean pivot into internal network addresses. Second SSRF fix for this exact function to get bypassed. If you rely on the whitelist, disable redirect-following (`follow_location => false`) in the stream context or manually re-validate every hop; no patched version yet.

PHPSpreadsheet: Gnumeric reader unbounded gzip expansion causes memory exhaustion

The Gnumeric reader calls gzdecode() on the full contents of any file with gzip magic bytes during canRead() — before it's even confirmed to be a valid Gnumeric file — with no decompressed-size cap, so a tiny compressed upload can exhaust the PHP memory limit and crash the worker. Reachable purely through PhpSpreadsheet's automatic file-type detection, so any app that accepts arbitrary spreadsheet uploads and lets the library sniff the format is exposed. No patch yet; cap request memory and reject files by extension rather than trusting canRead() to fail safely.

PHPSpreadsheet: XLS/OLE sector-chain self-loop causes memory exhaustion

The legacy XLS/OLE reader walks small-block sector chains from attacker-controlled header data with no cycle detection or max-length check, so a malformed .xls a few KB in size that points its sector chain back at itself makes OLERead::read() append the same block forever until memory runs out. Same disclosure batch and same root shape as today's Gnumeric bug — PhpSpreadsheet's file-type sniffing keeps tripping over untrusted, malformed spreadsheet uploads. No patch yet.

PostCSS: Arbitrary file read and information disclosure via attacker-controlled sourceMappingURL in CSS comments

PostCSS parses the `/*# sourceMappingURL=PATH */` comment from any CSS it processes and reads PATH off local disk with zero scheme, allowlist, or traversal check — reachable with plain `postcss().process(css)` and no options set, so any pipeline that runs untrusted CSS (theme uploads, CSS-in-JS build steps, blog comment renderers) gets an arbitrary-file-read plus a ~10-byte content leak via the JSON.parse error message. PostCSS sits under webpack, Vite, Next.js, and most CSS-in-JS toolchains, so the blast radius is anywhere a build or runtime pipeline touches attacker-influenced CSS. No patched release yet — the only mitigation today is passing `{ map: false }` explicitly.

Auth.js: OAuth state, nonce, and PKCE check cookies are not bound to the provider that created them

Auth.js stores OAuth anti-CSRF check values (state, nonce, PKCE verifier) in cookies that aren't bound to the provider that minted them, so in a multi-provider app that allows logged-in account linking, a check value from one provider's flow can satisfy a different provider's callback and link an attacker's account to a victim's session. Requires luring the victim into a same-origin flow, so it isn't pure CSRF — but it's the fourth Auth.js advisory in today's batch. Turn on `checks: ['pkce']` for every provider that supports it as the interim mitigation.

pypdf: Possible large memory usage for wrong image dimensions

A crafted PDF with image-dimension metadata far larger than the actual embedded data drives pypdf's image loader to over-allocate memory — cheap DoS for any server that renders or extracts images from untrusted PDFs. Fixed in pypdf 6.14.0.

pypdf: Possible long runtimes for repeated malformed cross-reference entries

Repeated malformed cross-reference stream entries send pypdf's parser into long runtimes on a small crafted PDF — a companion DoS disclosure to the image-dimension bug above, both fixed in pypdf 6.14.0. Bundle the upgrade together.