v vanemmerik.ai / SUPPLY-CHAIN
Supply Chain · Watch Thursday · 09 July 2026 End-of-day synthesis 4 watches · 33 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 — Late escalation at 21:00 ET: a fresh GHSA batch lands three more high-severity disclosures — header-leak and memory-exhaustion bugs across Elixir's two workhorse HTTP clients, Tesla and Mint — on top of a day already shaped by a three-ecosystem wallet/payment-credential wave and a 13-advisory YesWiki teardown.

Three unrelated campaigns hit three different package ecosystems today with the same playbook: fake or hijacked SDKs quietly exfiltrating wallet keys and payment-card data. Socket and Aikido caught a compromised Injective SDK on npm spreading a wallet-key stealer into 17 downstream packages, Socket separately flagged a typosquatted Braintree package on NuGet skimming live card numbers, and a 222-repo GitHub network staged Windows malware behind a malicious Go module — three ecosystems, one shape.

The rest of the day belonged to repeat offenders and single-vendor teardowns. YesWiki absorbed 13 advisories in one hour, including two independent paths to RCE and an unauthenticated bug that lets anyone delete arbitrary wiki pages; DSpace's path-traversal disclosure from this morning turned out to chain into Velocity-template RCE, its fourth advisory in two days; and NL Portal picked up a fourth authorization gap this month, this time letting any user tamper with someone else's task. Two AI coding-agent tools, Joro and Serena, disclosed the identical shape of bug — an unauthenticated localhost dashboard reachable from a browser tab, escalating to code execution — worth a specific look if agentic dev tools run unattended on your machine.

The bright spot: npm 12 ships with install scripts disabled by default, closing the postinstall-hook vector behind most of this year's npm campaigns, including today's Injective SDK compromise. Late escalation at 21:00 ET: a GHSA batch published after the evening synthesis locked adds three more high-severity items — Tesla's FollowRedirects middleware leaks the Authorization header on cross-origin redirects via a case-sensitivity bypass, Mint's HTTP/2 stack has no cap on PUSH_PROMISE or CONTINUATION-frame accumulation (memory-exhaustion DoS), and Mistune picked up a quadratic-time DoS in its Markdown link-text scanner. None of these are under active exploitation — this reads as disclosure hygiene from an Elixir HTTP-client audit round, not a new campaign — but Tesla and Mint sit underneath a lot of Elixir services that follow redirects or parse HTTP/2 from untrusted origins.

→ Operational priority for the night pull the latest YesWiki release wholesale rather than patching the 13 advisories piecemeal, check whether any AI coding agent on your machine — Joro, Serena, or similar — exposes an unauthenticated local dashboard before you leave it running overnight, and if you run Tesla or Mint in production, patch past 1.18.3 / 1.9.0 before your next deploy.

21:00 ET · Last Watch

Tesla, Elixir's most-used HTTP client, ships a five-advisory batch: Authorization-header leak on redirect, atom-table exhaustion, and a decompression bomb

Three high-severity bugs land in one Tesla release: FollowRedirects strips the Authorization header before a cross-origin redirect using a case-sensitive check against lowercase 'authorization', so any caller that sets the RFC-7235-canonical 'Authorization' casing leaks bearer tokens to the redirect target; the Mint adapter passes every request's URL scheme through String.to_atom/1 with no allow-list, so a scheme-varying attacker can exhaust the BEAM's fixed atom table and crash the VM; and DecompressResponse inflates gzip response bodies with no size cap, so a tiny attacker-controlled payload can expand into gigabytes of heap. All three are triggered by the server on the other end of the request, not by local input — exactly the shape that bites when a Tesla client follows redirects or fetches from an untrusted endpoint. Upgrade past 1.18.3 and audit any Tesla pipeline that follows redirects while carrying credentials.

Mint — the HTTP/1 and HTTP/2 client under Finch and much of Elixir's HTTP stack — picks up two unbounded-memory DoS bugs and a Content-Length smuggling primitive

Mint's HTTP/2 client inserts every inbound PUSH_PROMISE into a per-connection stream map with no regard for max_concurrent_streams, so a malicious server can flood promises and withhold the matching HEADERS to pin memory indefinitely; a sibling bug accumulates CONTINUATION frames into an uncapped buffer, so a HEADERS frame that omits END_HEADERS lets the same kind of server drive memory to exhaustion over a single connection — the same CONTINUATION-flood class that hit several major HTTP/2 stacks last year. A lower-severity Content-Length parser also accepts a non-RFC leading '+' sign, a response-smuggling primitive on any deployment fronted by a strict proxy that parses the header differently. Upgrade past 1.9.0; this landed in the same disclosure round as the Tesla batch above, so treat any Elixir service on either library as due for a patch pass.

Mistune's Markdown parser has quadratic-time blowup in link-text scanning (CVSS 7.5)

Mistune's parse_link_text repeatedly re-scans the remaining input with a regex search inside a loop, so a small Markdown snippet of repeated '[' characters forces roughly O(n²) behavior and hangs the parsing thread. Mistune sits under a lot of Python doc pipelines and static-site generators, and anywhere it renders user-submitted Markdown — comment systems, README previews, wiki-style docs — inherits the DoS from ordinary-looking input. Upgrade past 3.3.0 and cap Markdown input size ahead of any renderer you can't patch immediately.

GoBGP: confederation validator panics on empty AS_PATH, and a capability parser can read past its declared CapLen boundary

A zero-length AS_PATH attribute reaches an unchecked p.Value[0] access in GoBGP's confederation validator, letting a configured confederation eBGP peer crash the process with a malformed UPDATE; a second bug lets a malformed BGP OPEN message with CapLen==0 cause the 4-octet-AS capability parser to read bytes belonging to the following capability instead. Both require an already-established peering relationship, so this is hardening against a compromised or misconfigured peer rather than a pre-auth bug. Patch if you run GoBGP as a confederation border speaker or otherwise parse OPEN messages from peers you don't fully control.

psd-tools writes embedded smart-object content to an unsanitized path taken from the PSD file — arbitrary file write

SmartObject.save() writes an embedded smart object to a filename taken verbatim from the PSD file, so a crafted .psd with an absolute or ../-traversing smart-object name writes attacker-chosen bytes outside the intended output directory during ordinary extraction. Any pipeline that auto-extracts smart objects from untrusted uploads — design-asset ingestion, thumbnail generators — inherits arbitrary file write. Upgrade past 1.17.0 and don't extract smart objects from an untrusted PSD into a directory you can't afford to have overwritten.

sigstore-go's multi-log threshold verification counts witnesses per-entry, not per-log-authority — a single compromised log can satisfy an N>1 requirement

A verifier configured with WithTransparencyLog(N>1) or WithSignedCertificateTimestamps(N>1) is meant to require independent confirmation from multiple logs as defense-in-depth against one log being compromised. sigstore-go instead counted verified witnesses per-entry or per-validation-path, so a single compromised transparency log or CT log can forge or replay enough entries to satisfy the threshold alone. This matters more than the medium CVSS suggests because sigstore-go underpins keyless-signing verification for cosign and npm/PyPI provenance checks — a verifier that believed it required two independent logs was really trusting one. Upgrade, and re-verify any artifact whose trust decision depended on an N>1 configuration.

Rattler's conda package cache is vulnerable to path traversal via an untrusted channel's build-string field

rattler_cache builds its package-cache key by joining the conda package record's build string directly into a filesystem path, so a malicious or untrusted conda channel can publish repodata with path-traversal components in that field and write package contents outside the configured cache directory. Curated, validated channels aren't exposed, but conda's channel model makes adding an extra unvetted channel a routine, low-friction action. Upgrade rattler_cache/py-rattler and treat any non-default conda channel as untrusted input to the cache layer.

OpenRun's redirect-URL validator can be bypassed with a protocol-relative '//host' path — open redirect

OpenRun validates that a redirect's host and scheme match the current site before honoring it, but a value starting with '//host' bypasses the check — browsers treat a leading '//' as a protocol-relative absolute URL, and the validator's same-host logic doesn't parse it that way. It's a classic open-redirect bypass shape: validate the parsed host, not a string prefix. Upgrade past 0.17.7, and grep any hand-rolled redirect-URL validation elsewhere in your stack for the same gap.

pypdf's writer enters an infinite loop when merging a PDF with threads/articles metadata

Merging a crafted PDF that carries threads/articles metadata into a pypdf writer triggers an infinite loop, hanging the process on nothing more than an ordinary merge call. Upgrade past 6.13.1, or apply the fix from PR #3839 if you can't upgrade yet, and wrap any merge of untrusted PDFs in a timeout in the meantime.

18:00 ET · First Watch

Socket catches a typosquatted Braintree NuGet package skimming live credit-card data and merchant credentials

A malicious .NET package typosquatting the real Braintree SDK on NuGet skims live payment-card numbers and harvests merchant API keys and host secrets straight out of production checkout flows. It's the same typosquat-plus-credential-exfiltration shape as the Injective SDK and Go-module campaigns disclosed earlier today, just aimed at NuGet instead of npm or Go — treat package-name similarity to any payment SDK as a red flag this week. Audit your NuGet lockfile for the exact package name Socket flagged and rotate any Braintree credentials a recent build touched.

YesWiki: 13 advisories land in one hour — two RCE paths, an unauthenticated mass page-deletion bug, and a stack of SQLi/XSS/SSRF

A single audit dropped 13 YesWiki advisories within an hour: unsafe eval() in the Bazar formula calculator (ReDoS crash or RCE via validation bypass), unserialize() with no allowed_classes guard enabling PHP object injection, an unauthenticated {{erasespamedcomments}} action that deletes arbitrary wiki pages under YesWiki's default allow-by-default ACL model, an admin-authenticated Twig SSTI confirmed to full RCE, plus SQLi in ReactionManager and the entry-listing API, an unauthenticated SSRF via ActivityPub signature keyId, and several stored/reflected XSS bugs. This is a full-surface teardown of one CMS, not a single bug — if you run YesWiki, don't patch piecemeal; pull the latest release wholesale and re-audit any custom Bazar templates or ACLs layered on top.

Joro's default proxy mode runs an unauthenticated, wildcard-CORS plugin-upload API on localhost — one page visit to RCE

Joro's proxy mode binds an unauthenticated API to 127.0.0.1:9090 with a wildcard CORS policy, and because plugin uploads use the CORS-safelisted multipart/form-data type, any cross-origin page the operator's browser visits can upload and trigger a native plugin with no preflight or credentials. Plugins execute on load, so a single malicious tab gives an attacker code execution as the operator's own user — the same class of localhost-CORS bypass that's burned other local dev tools. Upgrade past 1.1.0 and don't rely on 127.0.0.1 binding as a security boundary against browser-borne requests.

Nuclio's cron-trigger controller builds a shell command from unsanitized event headers and body — persistent RCE in the CronJob

Nuclio's controller assembles a curl invocation for every cron trigger and stores it as shell args in a Kubernetes CronJob container; event.headers keys are interpolated verbatim inside double-quoted arguments and event.body is escaped for quotes but not for $() command substitution, so either field lets an attacker break out into arbitrary command execution that persists in the CronJob spec. CVSS 9.9 — this is a serverless platform executing attacker-supplied trigger config as shell, not application code, so the blast radius is the whole cluster node the CronJob runs on. Patch past the 2026-06-01 dev build and treat cron-trigger event fields as untrusted input anywhere they reach a shell.

DSpace's LDN path-traversal bug from this week's batch chains into RCE via Velocity template reflection

The COAR Notify/LDN path traversal DSpace disclosed alongside this morning's batch (GHSA-9qm4-rh6w-pq5x) turns out to be the first half of an attack chain — an admin-credentialed attacker can use that traversal to reach Velocity templates and execute Java via reflection, escalating what looked like a privileged path-traversal bug into full RCE. This is the fourth DSpace advisory in two days and the first to confirm code execution rather than file read/write; if you triaged this morning's batch as "contained, admin-only," re-open it — the ceiling is now RCE. Patch to 8.4/9.3/10.0-rc2 and treat any DSpace admin or collection-admin account compromise as a potential RCE, not just a data-access incident.

laravel-backup-restore shells out to mysql/psql/gunzip with an unescaped filename pulled from the archive — OS command injection on restore

The restore workflow extracts a ZIP, converts the dump filename to an absolute path, and interpolates it unescaped into shell command strings passed through Symfony's fromShellCommandline() — so a crafted backup archive with shell metacharacters in its dump filename executes arbitrary commands the moment someone restores it. Backup-restore tooling is exactly the kind of thing run with elevated privileges against files that arrive from outside the org — a vendor handoff, a migration, a support-ticket attachment. Upgrade past 1.9.3, and until then, never restore a backup archive you didn't produce yourself without inspecting the dump filenames first.

Serena's AI-coding-agent dashboard binds an unauthenticated Flask API to a fixed port — DNS rebinding to memory poisoning to RCE

Serena's built-in dashboard runs an unauthenticated Flask server on a hardcoded, predictable port (24282) with no CSRF protection or Host header validation, so a DNS-rebinding attack from any browser tab can reach it and write arbitrary content into the agent's persistent memory store — memory the agent later reads and acts on autonomously. Combined with execute_shell_command enabled by default (shell=True), that's a full RCE chain triggered by nothing more than the victim visiting a malicious webpage while Serena is running in the background. Upgrade past 1.5.2; if you run any AI coding agent with a local dashboard, confirm it isn't reachable from a browser tab without auth — same shape as the Joro bug above, different tool.

NL Portal's task-submission endpoint never checks task ownership — fourth authorization gap disclosed this month

Any authenticated portal user could submit or overwrite another user's open task by guessing or obtaining its ID — completing it, tampering with the submitted data, and reading back the original owner's form contents in the GraphQL response. That's the fourth nl-portal-backend-libraries authorization gap disclosed this month (after two more GraphQL resolver gaps found earlier today), all tracing to the same root cause: ownership checks present on some endpoints but never ported to others. If you run nl-portal, this is no longer a one-off — commission a full authz audit across every REST and GraphQL endpoint rather than patching each disclosure as it lands.

Sylius ships three shop-API authorization bugs in one release: payment-request IDOR, channel-restriction bypass, and completed-order corruption

Three distinct bugs land in one Sylius release: a payment-request endpoint that authorizes on a URL hash alone, leaking the order's token and letting an attacker redirect the buyer post-payment; a channel-restricted payment-method check enforced on checkout but missing on the account endpoint, letting customers assign disallowed payment methods; and a stale-cart LiveComponent that deletes or corrupts an order that's already been completed in another tab. Only the first is attacker-initiated in the classic sense — the third is a data-integrity bug triggerable by a customer's own concurrent browser tabs. Upgrade to 2.0.18/2.1.15/2.2.6 and audit any custom checkout flow built on Sylius for the same hash-only-lookup pattern.

npm 12 disables install scripts by default and deprecates granular access tokens that could bypass 2FA

GitHub's npm 12 flips allowScripts to off by default, closing the install-script-as-dropper vector behind a large share of this year's npm supply-chain campaigns — including today's Injective SDK compromise and several recent wallet-stealer packages — and deprecates granular access tokens that could bypass 2FA. This is the single biggest structural change to npm's attack surface in years; most of what Socket and Aikido catch weekly runs via a postinstall hook. If you maintain packages with legitimate install-time build steps, audit them now for the explicit allowScripts opt-in before npm 12 lands in your CI.

12:00 ET · Forenoon Watch

Socket and Aikido both catch a compromised Injective SDK npm package exfiltrating wallet keys and mnemonics

Socket found wallet-key and mnemonic exfiltration hidden inside fake telemetry code in the Injective SDK (npm) version 1.20.21, which then spread the same payload into 17 more npm packages; Aikido independently confirmed the campaign hours later. It's the same fake-telemetry dropper shape used against other wallet/crypto SDKs this year, so treat any recently-updated wallet-adjacent SDK the same way until vetted. If your build pulled @injectivelabs/sdk-ts or any of the 17 flagged packages recently, rotate any keys or mnemonics a build process touched and pin to a version predating 1.20.21.

Craft CMS: fourth recurrence of the same missing-cleanseConfig RCE pattern, plus an authenticated SVG path traversal

Craft CMS's FieldsController::actionRenderCardPreview() skips the cleanseConfig() call every sibling controller uses, so an authenticated admin session can inject a Yii2 ‘on eventName’ handler into the field-layout config for arbitrary code execution — the fourth time this exact missing-sanitization pattern has been disclosed against a different Craft CMS controller this cycle. A lower-severity authenticated path traversal rides along in the same release, letting a logged-in user read local .svg files via the assets/icon endpoint. If you maintain a Yii2-based CMS fork, grep every controller that builds a config array from POST data for a missing cleanseConfig() call — this vendor keeps finding them one at a time.

Soup Sieve — Beautiful Soup's CSS selector engine — ships two DoS bugs: a 300-byte ReDoS and unbounded-memory selector compile

Soup Sieve, the CSS selector engine under every Beautiful Soup 4 install, has a regex in its attribute-value parser vulnerable to catastrophic backtracking — a 300-byte unterminated-quote payload hangs it for 3+ seconds — and a separate bug lets a large comma-separated selector list allocate hundreds of megabytes on compile. Any service that runs .select() or .select_one() against attacker-influenced HTML or selector strings inherits both, and bs4's ubiquity in scraping and parsing pipelines makes this a wide blast radius for a low-effort attack. Upgrade past 2.8.3 and cap the size of any selector string built from user input.

Micronaut's HTTP client follows redirects with no cap and forwards Authorization/Cookie headers cross-domain

Micronaut's Netty-based HTTP client imposes no maximum redirect count (infinite-loop DoS) and, worse, forwards Authorization, Cookie, and Proxy-Authorization headers to the redirect target even across domain boundaries — the header blocklist only strips Host/Connection/TE/CT/CL. A malicious or compromised redirect target can walk off with a caller's bearer token or session cookie with nothing more than a cross-domain 302. Upgrade to 3.10.7 / 4.10.24 / 5.0.1 and audit any Micronaut client that follows redirects to external hosts while carrying credentials.

Ruby's css_parser gem: unrestricted @import fetches escalate SSRF to arbitrary local file disclosure via redirect

css_parser's read_remote_file fetches any host/port/URI it's handed with no allowlist, and because it follows Location redirects recursively back into the same function — which also services file:// URIs — a single attacker-controlled redirect upgrades a plain SSRF into arbitrary local file disclosure. Anything that runs css_parser against user-supplied stylesheets or URLs (theming engines, PDF-from-HTML pipelines) inherits this. Upgrade to 3.0.0, and if you can't, block file:// and redirect-following in front of any code path that hands css_parser external input.

Phantom's MCP audio tools accept unconfined absolute output paths — arbitrary file write to shell startup files

Phantom's MCP tools accept arbitrary absolute output paths with no confinement when PHANTOM_OUTPUT_DIR is unset, the default, so any AI agent driving the MCP interface can write or overwrite files the process user can touch — including ~/.zshrc or a DAW startup script, effectively local code execution on a developer's machine. A separate, unguarded audio-decode path also allows a decode-bomb DoS. Set PHANTOM_OUTPUT_DIR explicitly and upgrade past 1.3.0 before letting an agent drive Phantom's MCP tools unattended.

HAPI FHIR's validator evaluates unvalidated FHIRPath expressions from incoming resources — ReDoS via evil regex

Every FHIRPathEngine implementation in HAPI FHIR's validator stack evaluates FHIRPath matches()/replaceMatches() expressions from an incoming resource with no input validation, so a crafted resource containing an evil regex pattern triggers catastrophic backtracking and exhausts the validator. Anything running the FHIR Validator as an HTTP endpoint against untrusted resource submissions — a common pattern in healthcare interop pipelines — is exposed to a trivial DoS. Upgrade past 6.9.9 (or 6.9.4.2 on the older line) and rate-limit or sandbox validator calls that process external FHIR resources.

Note Mark: unanchored slug regex enables path traversal in export CLI, plus unauthenticated soft-deleted-note disclosure

Note Mark validates book/note slugs with an unanchored regex, so a slug like ‘../../../../tmp/escape’ passes validation and lets the migrate-export CLI write files outside the target directory. A sibling bug lets any unauthenticated caller enumerate soft-deleted note metadata on public books via ?deleted=true, because the query bypasses GORM's soft-delete scope without updating the authorization clause to match. Anchor slug patterns end-to-end (^...$) and treat every new query parameter as new authorization surface, not just a new filter.

DSpace adds three more path-traversal/URI-validation advisories on top of last week's four-bug batch

DSpace picked up three more advisories in the same shape as last week's batch: an LDN message template path that isn't restricted to a known base directory, a Curation Task reporter output path with the same gap, and an OAI-ORE ingestion crosswalk that doesn't validate the URI scheme (accepting file:///etc/passwd). All three require existing DSpace admin or collection-admin credentials, so this is privilege escalation from a trusted role rather than a pre-auth path. Confirm curation, LDN, and OAI-ORE admin roles are tightly held, and pin output/template paths to an allowlisted base directory.

pyLoad: unbounded EventManager memory growth, plus an IPv6 transition-address SSRF guard bypass

pyLoad's EventManager creates a Client object for every unique UUID hitting the events API and never calls its own cleanup method, so an ordinary API caller can grow memory unbounded into a DoS. A second bug in the same release lets pyLoad's SSRF guard be bypassed via IPv6 6to4/NAT64 transition addresses that wrap internal IPv4 ranges, since is_global doesn't unwrap them before checking. Upgrade past 0.5.0b3.dev100, and don't rely on ipaddress.is_global alone — resolve and re-check the underlying IPv4 for any IPv6 transition prefix.

Gittensory's MCP tool and REST endpoint both leak miner financial data past a missing contributor-scope check

Gittensory's contributor-profile REST endpoint and its matching gittensory_get_contributor_profile MCP tool both skip the contributor-scoped access check every sibling endpoint enforces, so any authenticated token holder can pull another miner's daily TAO/alpha/USD revenue (plus hotkey via the REST path). It's the same class of oversight as recent MCP-tool disclosures this month — a redaction filter that catches obvious secret-shaped keys but misses the actual sensitive fields it was meant to protect. Add the contributor-scope gate to both the REST route and the MCP tool, not just one.

NL Portal's GraphQL layer skips per-user authorization on documents and decisions — third authz gap this month

Two more nl-portal-backend-libraries GraphQL resolvers — document content and decision (besluiten) records — return data with no check that the caller owns it; the document resolver has been missing this check since its first 2022 commit, so every published version is affected. This is the third NL Portal authorization gap disclosed this month, and all three trace to GraphQL resolvers that never got the parity checks the REST layer already has. If you run nl-portal-backend-libraries, audit every GraphQL resolver against its REST equivalent for parity, not just the ones already patched.

pymonocypher's argon2i_32 binding skips buffer-size validation — heap corruption on undersized nb_blocks

pymonocypher's argon2i_32 binding never checks that the caller-provided buffer is large enough for nb_blocks, so an undersized buffer causes the underlying C implementation to write past its end and corrupt the heap — a memory-safety bug in a password-hashing primitive, not a cosmetic one. Fixed in 4.0.2.8. If you call argon2i_32 directly, upgrade rather than trying to validate buffer size yourself at the call site — this exact class of bug is easy to reintroduce.

06:00 ET · Morning Watch

Socket uncovers 'Operation Muck and Load' — a 222-repo GitHub network staging Windows RAT and infostealer malware behind a malicious Go module

Socket is tracking a threat actor running commit-farming workflows and public dead drops across 222 GitHub repositories to distribute a malicious Go module that stages Windows RAT and infostealer payloads via password-protected archives. The scale and use of farmed commit history as camouflage matches the pattern of recent GitHub-Releases-as-dropper campaigns — treat any unfamiliar Go module with a suspiciously deep, farmed commit history as unvetted. Check go.sum and CI logs for pulls from the repos Socket has flagged before trusting a new Go dependency this week.