v vanemmerik.ai / SUPPLY-CHAIN
Supply Chain · Watch Wednesday · 16 September 2026 End-of-day synthesis 4 watches · 43 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: djust's auth-boundary collapse grew from eight CVEs to twelve after First Watch locked the day's shape, the worst a WebSocket/SSE mount path that lets an unauthenticated client force the server to import and run any Python module by name — RCE-by-proxy — while rmcp, the Rust MCP SDK, separately disclosed an unauthenticated session-leak DoS and an OAuth flaw that lets a malicious MCP server steal access tokens.

Late escalation at 21:00 ET: djust wasn't done. GHSA published four more djust advisories between 22:02 and 22:09 UTC — after First Watch had already locked the day's story at eight CVEs — pushing the release's total to twelve. The worst of the new four needs no prior authentication at all: the WebSocket/SSE mount path resolves the view to load from a client-supplied dotted path and calls __import__() on it before checking the result is a LiveView subclass or running any auth, so an anonymous client can force the server to execute the import-time side effects of any importable Python module. That's RCE-by-proxy on any host with a side-effectful dependency, and it's arguably worse than this morning's WebSocket auth-bypass because it doesn't require the attacker to already be inside an authenticated session.

Separately, rmcp — the Rust MCP SDK — disclosed two issues in the same window. Its Streamable HTTP transport allocates a session before validating the request body and never releases it on failure, so a single unauthenticated POST leaks one permanent session-table entry; researchers sustained over 2,000 leaks/sec, extrapolating to roughly 75GB/day of resident memory. A second rmcp advisory found its OAuth Protected Resource discovery skips the RFC 9728 resource-parameter check, letting a malicious MCP server redirect the flow and steal the resulting access token. Anyone running MCP infrastructure on rmcp's HTTP transport should treat both as one patch cycle.

The bright spot holds even with the escalation: all twelve djust CVEs — this morning's, First Watch's, and tonight's — ship in the same 1.0.7 release, so it's still one upgrade, not four.

→ Operational priority for the night if you run djust, confirm you're on 1.0.7 — this is the third pass today flagging it, and tonight's arbitrary-module-import bug is the most severe of the twelve. If you run an MCP server on rmcp's Streamable HTTP transport, patch that too; the session leak is a trivial unauthenticated DoS.

21:00 ET · Last Watch

djust — unauthenticated arbitrary module import on the WebSocket/SSE mount path

djust's live transport resolves the view to mount from a client-supplied dotted path and calls __import__() on it before checking the result is a LiveView subclass or running any auth — the allowlist meant to gate this is fail-open when unset, which is the framework default. An unauthenticated WebSocket or SSE client can send a mount frame naming any importable Python module and force the server to run that module's import-time side effects: RCE-by-proxy on any host with a side-effectful dependency, plus a free module/class enumeration oracle from the error strings. Fixed in 1.0.7 with the rest of the cluster — of djust's now twelve CVEs today, this is the one that doesn't need an existing session to exploit.

djust — broken object-level access control (IDOR) outside the WebSocket path

djust enforces per-object authorization (ADR-017) on WebSocket mount and event handling, but not on the initial HTTP GET render, SPA url_change navigation, or {% live_render %} embedded children — an authenticated user can reach an object they're not authorized for through any of those three paths. Fixed in the same 1.0.7 release as the transport auth-bypass; if you're patching djust tonight for the WebSocket bug, this is why the upgrade needs to be the whole release, not a targeted backport.

@nuxtjs/mdc — SVG xlink:href and data:text/html bypass the markdown URL sanitizer

@nuxtjs/mdc's sanitizer only scheme-checks attributes literally named href or src, so a javascript: URL on an SVG xlink:href or a data:text/html payload passes straight through at the default configuration — the third bypass of the same sanitizer across three advisories. Raw HTML is enabled by default (allowDangerousHtml: true), so any app rendering untrusted markdown through mdc's stock config has stored XSS until patched.

rmcp — unauthenticated session-table leak in Streamable HTTP transport is a remote DoS

rmcp's Streamable HTTP server allocates a session before validating the JSON-RPC body, then never calls close_session on a validation failure — a single well-formed non-InitializeRequest POST leaks one permanent session-table entry. Researchers sustained over 2,000 leak requests/sec, extrapolating to roughly 75GB/day of resident memory from an unauthenticated client. If you're running an MCP server on rmcp's Streamable HTTP transport, this is a trivial remote DoS; patch before exposing it further.

rmcp — missing resource-field validation lets a malicious MCP server steal OAuth tokens

rmcp's OAuth Protected Resource metadata discovery skips the RFC 9728 resource-parameter check, so a malicious MCP server can point the client at a legitimate authorization server and walk off with the resulting access token. Same crate, same disclosure window as the session-leak bug above — if you're auditing rmcp-based MCP clients tonight, do both at once.

djust — dropped Host header on the WebSocket path misresolves tenants

djust's WebSocket request reconstruction omits the client Host header, so Host/subdomain TenantResolvers default to "testserver" on the live path — with STRICT_MODE=False that returns unscoped, cross-tenant rows; otherwise it silently returns nothing. Same 1.0.7 fix as the rest of the cluster; worth checking if your tenant isolation depends on Host-based resolution.

djust — no sensitive-field denylist on serialized Django models sent to the client

Any Django model instance assigned to a public djust view attribute was serialized to the client with no sensitive-field denylist — password hashes, is_staff/is_superuser flags, and other PII crossed the wire by default. Fixed in 1.0.7 alongside the rest of the cluster; audit view attributes for raw model instances if you've been running an earlier version.

18:00 ET · First Watch

djust — WebSocket/SSE transport bypasses Django's entire authorization stack, including admin views

djust's live transport authorizes a mount via its own check_view_auth instead of Django's View.dispatch() chain, so LoginRequiredMixin, PermissionRequiredMixin, custom dispatch() guards, and even the admin extension's staff gate are enforced on the initial HTTP GET but silently skipped over WebSocket — where all events and state actually flow. An anonymous client can open a WebSocket, mount an admin list/create/change/delete view, and dispatch its handlers directly; this is the fifth djust CVE published today and the worst of the batch (CVSS 9.1) because it swallows every other auth control at once. Fixed in 1.0.7, which makes check_view_auth honor the Django AccessMixin family on every transport — if you're upgrading djust for the earlier CSRF/tenant-isolation/mass-assignment fixes, this is why 1.0.7 isn't optional.

CISA adds a Cisco ISE privileged-API authentication bypass to KEV

Cisco Identity Services Engine and ISE-PIC contain an incorrect-use-of-privileged-APIs bug that lets an unauthenticated remote attacker bypass the web management interface entirely, and CISA has catalogued it as actively exploited with a September 19 due date. ISE is core network-access-control infrastructure — an attacker who can reach its management interface can potentially reshape who else gets network access. Patch to Cisco's fixed release now regardless of your normal ISE maintenance window.

CISA adds an Acronis Backup plugin privilege-escalation bug to KEV

Acronis's Backup plugin for cPanel/WHM and its Plesk extension ship with incorrect default permissions that allow privilege escalation, now catalogued as actively exploited with a September 19 due date. If you run Acronis Backup through either control panel integration, this is a hosting-control-plane compromise path, not just a backup-data risk — patch on CISA's timeline.

djust — unsigned client-side state snapshot restored as trusted view state on reconnect

For views that opt into state snapshots, djust restores the client-supplied state_json on reconnect with no integrity check, so a client can edit is_admin, account_id, or any public view attribute in their own page and have it trusted on the next mount frame. Sixth djust CVE today; fixed in 1.0.7 by signing snapshots and rejecting unsigned or forged ones on the back-navigation restore path. Don't hold authorization state in public view attributes regardless of patch level.

djust — SSE sessions keyed only by a client-chosen session_id, no binding to the authenticated user

The WebSocket transport binds a session to its authenticated principal; SSE dropped that control, so an attacker who learns a session_id can dispatch event handlers that execute with the victim's identity and state — a straight session-hijack, not just a CSRF variant. Seventh djust CVE today; fixed in 1.0.7 by binding each SSE session to its owning principal at creation and capping sessions per principal.

node-opcua — clock-skew keepalive failure leaks a TCP socket per reconnect, OOMs the client

node-opcua's keepalive manager treats a server's BadInvalidTimestamp response — which just means client/server clocks disagree beyond tolerance — as a fatal network error and forces a full reconnect; the reconnect handler then calls socket.end() instead of socket.destroy() on a failed HEL/ACK, leaving the socket in FIN-WAIT-2 forever if the peer (commonly a PLC) doesn't close its side. At the default 3-second keepalive interval that's roughly 1,200 leaked sockets an hour until the process OOMs — no attacker required, just an OPC UA server with clock drift. No patched version yet; if you run node-opcua against industrial PLCs, check NTP sync on both sides and consider disabling keepSessionAlive until a fix lands.

djust — built-in component tags render javascript: URLs unescaped into href/action

djust's breadcrumb, nav, citation, and form-action component tags HTML-escape a developer-supplied URL before rendering it into href/action, which stops attribute breakout but does nothing to a javascript: URI, which needs no escapable characters — a scheme value of javascript:alert(document.cookie) lands verbatim and executes on click. Eighth and last djust CVE in today's batch; the fix adds a safe_url() helper that neutralizes javascript:/vbscript:/data: schemes before the escape step. Conditional on an app passing user-controllable URLs into these components, hence medium.

12:00 ET · Forenoon Watch

LMdeploy — unauthenticated RPC server deserializes pickle, unpatched RCE

LMdeploy's RPC server deserializes incoming messages with pickle.loads() with no sanitization in zmq_rpc.call_and_response(), so anyone who can reach the RPC port gets arbitrary code execution — a working PoC ships with the advisory. This is the same insecure-deserialization shape that's burned countless ML-serving stacks; don't expose LMdeploy's RPC interface to any network you don't fully trust, and there's no patch yet.

@zereight/mcp-gitlab — unauthenticated SSE transport + arbitrary file read chains to full GitLab takeover

@zereight/mcp-gitlab's SSE transport — the mode Docker deployments use by default — ships with zero authentication, and its upload_markdown tool reads arbitrary local files via an unsanitized path and uploads them to GitLab. Chain the two and any network-reachable attacker reads /proc/self/environ, steals the server's GITLAB_PERSONAL_ACCESS_TOKEN, and takes over the GitLab account outright — in the default Docker config. If you run this MCP server, take it off the network immediately; no patch exists yet.

@zereight/mcp-gitlab — DNS rebinding reaches the local Streamable HTTP MCP listener

Third mcp-gitlab finding: the Streamable HTTP MCP endpoint has no effective Host/Origin allowlist, so a malicious webpage can use DNS rebinding to reach a victim's local MCP listener while spoofing the Host and Origin headers past the initialization check. Classic CWE-350 — if you run mcp-gitlab locally for an IDE integration, don't assume localhost binding alone protects you.

Http4s Ember — accepts Transfer-Encoding with Content-Length, enabling CL.TE request smuggling

Http4s's Ember parser doesn't reject a request carrying both Transfer-Encoding and Content-Length, so an intermediary that strips-and-forwards by Content-Length disagrees with Ember about where the body ends — classic CL.TE request smuggling; RFC 9112 §6.1 requires rejecting this outright. This lands as part of a coordinated Ember disclosure batch (eleven more CVEs below); if you run Ember behind any reverse proxy or load balancer, patch this one first.

CISA adds a Google Pixel cellular-modem authorization bug to KEV

CISA added one new entry to KEV today: an improper-authorization bug in the cellular modem firmware on Google Pixel devices that lets an attacker bypass permission checks and escalate privileges, catalogued as actively exploited. Not an open-source supply-chain bug, but a KEV add is always the operational-priority signal regardless of ecosystem — fleet-managed Pixels should get the vendor mitigation on CISA's normal federal timeline.

Attacker hijacks an AI coding-assistant session to spread Shai-Hulud across ~100 repos

Mandiant reports an attacker hijacked an active AI coding-assistant session at an unnamed SaaS provider and used it to recommend a poisoned package — which got accepted — then rode that foothold to spread Shai-Hulud across roughly 100 internal repositories, stealing secrets and source code before the repos were disabled. This is a new vector for the same self-propagating worm family we've tracked since May: instead of phishing a maintainer or compromising a registry account directly, the attacker compromised the assistant's session and let it vouch for the malicious dependency. If your org gives AI coding assistants any package-install or PR-approval authority, treat their sessions with the same hijack scrutiny as an SSO cookie.

djust — CSRF on the Server-Sent-Events transport lets a cross-origin page drive a victim session

djust's SSE transport skips CSRF protection: the client→server POST endpoints are @csrf_exempt and the GET stream endpoint never checked Origin, so a cross-origin page can mount a victim-authenticated LiveView and fire state-changing event handlers as that victim — the session_id looks like a token but is just a client-chosen UUID. This lands alongside three more djust advisories today (tenant isolation, mass-assignment, exposed observability endpoints), all patched in 1.0.7 — treat it as one upgrade, not four.

djust — tenant isolation fails open on the WebSocket/SSE path, leaking every tenant's data

djust's tenant isolation was HTTP-only: the WebSocket/SSE path never set the thread-local tenant, so the tenant-aware QuerySet manager failed open and returned every tenant's rows to whoever held the socket, with threading.local additionally bleeding across connections on the async executor. If you run djust multi-tenant, this is a live cross-tenant data leak until you're on 1.0.7, which moves tenant state to a per-task ContextVar and fails closed by default.

djust — default update_model handler allows mass-assignment of any view attribute

djust's default update_model handler lets a client setattr any public view attribute by name — not just fields actually bound with dj-model= in the template — gated only by an underscore check and a 14-entry denylist of framework internals; the allowlist that would restrict this is opt-in and off by default. Any view that keeps authorization state like is_admin or account_id as plain attributes alongside a bound field is mass-assignable today; set allowed_model_fields explicitly and upgrade to 1.0.7.

djust — observability endpoints, including remote eval_handler, reachable outside DEBUG-only setups

djust's observability endpoints — including a remote eval_handler — are gated only by DEBUG mode plus an opt-in middleware the documented setup never installs, so a misconfigured-but-documented deployment leaves live session state and remote method invocation reachable from the network. Fourth djust fix in today's batch; 1.0.7 enforces the localhost check in-view instead of relying on the separate middleware. Confirm DEBUG=False in prod regardless.

OpenTelemetry.Resources.Host (NuGet) — PATH hijack on macOS leads to local code execution

OpenTelemetry.Resources.Host's macOS host-id detector launches sh and ioreg by bare name instead of absolute path, so a local attacker who can influence PATH or write ahead of it in the search order gets arbitrary code execution in the host application's context. Local-privilege-escalation bar, not remote, but it's the exact untrusted-search-path bug class worth grepping your own shell-out code for; check for a fixed release before your next .NET observability rollout.

@zereight/mcp-gitlab — SSRF via X-GitLab-API-URL header when dynamic API URLs are enabled

Same package, a second hole: with ENABLE_DYNAMIC_API_URL=true, mcp-gitlab trusts a client-supplied X-GitLab-API-URL header as the base for outbound API calls with no host allowlist, so an attacker can redirect the victim's Private-Token to an attacker-controlled host. Gated behind a non-default flag — GHSA rates it critical, the reporter's own CVSS scores it 8.5/high — but combined with the unauthenticated-SSE finding above it's another reason to isolate this server rather than patch around it. No fix at time of writing.

@zereight/mcp-gitlab — read-only mode, project allow-list, and transport auth all independently bypassable

Fourth mcp-gitlab issue rounds out the picture: execute_graphql defeats both read-only mode and the project allow-list, the Streamable HTTP transport can go unauthenticated under certain credential setups, and the session/transport-exhaustion DoS check is only syntactic. Read together, mcp-gitlab's entire safety model — read-only mode, allow-listing, transport auth — has holes in every layer; if your team runs this for LLM-agent GitLab access, pull it until a patched release lands.

Http4s Ember — case-sensitive Transfer-Encoding match enables TE.CL/TE.0 smuggling

Companion smuggling bug: Ember matches Transfer-Encoding case-sensitively, so "Transfer-Encoding: Chunked" (capital C) isn't recognized as chunked and Ember falls back to Content-Length framing while a compliant intermediary chunks the same bytes — TE.CL/TE.0 smuggling. Same fix window as the CL.TE issue above; patch both together.

Http4s Ember — HTTP/2 buffers a frame's full declared size before enforcing SETTINGS_MAX_FRAME_SIZE

Separately, Ember's HTTP/2 reader buffers a frame's full declared payload into memory before checking it against SETTINGS_MAX_FRAME_SIZE — up to 1024x amplification per connection over the 16 KiB Ember advertises, roughly 16 GiB of heap reachable at the default 1024 max connections. Unauthenticated and remote; if you run ember-server with HTTP/2 enabled, prioritize this one among today's five HTTP/2 resource-exhaustion findings.

Http4s Ember — unbounded CONTINUATION-frame accumulation exhausts heap

Second HTTP/2 exhaustion path: Ember buffers HEADERS/PUSH_PROMISE continuation fragments unbounded while waiting for END_HEADERS, so a connection that never sends the final fragment exhausts heap — no auth required, and it fires even on requests that would 404 since the attack completes before the request is decoded.

Http4s Ember — unbounded outbound HTTP/2 frame queue

Third: Ember serializes outgoing HTTP/2 frames through a single unbounded queue, and a peer can force cheap control-frame replies (PING ACK, SETTINGS ACK, WINDOW_UPDATE) faster than the writer fiber drains them, backing up the queue until the process OOMs from one unauthenticated connection.

Http4s Ember — HTTP/2 never enforces SETTINGS_MAX_CONCURRENT_STREAMS

Fourth: Ember never enforces SETTINGS_MAX_CONCURRENT_STREAMS, so one connection can open unbounded concurrent streams, each holding server state that's never released — the same resource-exhaustion shape as the HTTP/2 Rapid Reset family (CVE-2023-44487), just via open-not-reset streams instead.

Http4s Ember — HTTP/2 inbound body buffering ignores application backpressure

Fifth and last of the HTTP/2 batch: Ember's inbound flow-control window refills based on bytes received rather than bytes the application actually consumes, so flow control provides no real backpressure and a slow-draining app lets a fast peer buffer an unbounded body in heap — the mirror image of the outbound-queue bug above. All five HTTP/2 findings plus the three smuggling bugs ship in one Ember release; if you're running Ember in production, this is a single upgrade, not eight separate risk calls.

Http4s Ember — DigestAuth nonce map grows unbounded, persistent DoS

Unrelated to the HTTP/2 batch: Ember's DigestAuth stale-nonce cleanup has an inverted comparison — it deletes fresh nonces and stops at the first stale one — so the nonce map grows without bound on every unauthenticated challenge until the JVM OOMs. Persistent, unauthenticated DoS against any route using DigestAuth.

Http4s Ember — lenient chunk-size parsing enables TE.TE request smuggling

Third smuggling variant: Ember's chunk-size parser tolerates whitespace and a leading +/- sign where RFC 9112 requires strict hex digits, so an intermediary with a stricter parser disagrees on chunk boundaries — TE.TE smuggling. All three Ember smuggling bugs (CL.TE, TE.CL/TE.0, TE.TE) ship in the same release; there's no reason to patch one without the others.

Http4s Ember — DigestAuth nonce-count tracking allows replay of captured requests

Second DigestAuth bug: the replay-defense counter stores lastNc + 1 instead of the actual nc it just accepted, so non-contiguous nonce-counts from parallel or retried requests — which browsers send routinely — let a captured Authorization header be replayed several times, defeating Digest's core advantage over Basic auth.

Http4s — client CookieJar matches host by substring, leaking cookies cross-origin

Ember's client-side CookieJar middleware decides which requests get a cookie using an unanchored substring match instead of RFC 6265's domain match, so a cookie scoped to example.com is also sent to evilexample.com. If you use http4s as an HTTP client with CookieJar enabled, this leaks session cookies to any attacker-registered lookalike domain.

Http4s — client CookieJar trusts arbitrary Set-Cookie Domain, enabling session fixation

Companion CookieJar bug: incoming Set-Cookie Domain attributes are trusted verbatim with no domain-match or public-suffix check, so a malicious or compromised server can plant a cookie for any domain in the jar — session fixation against a victim domain the client later talks to. Both CookieJar findings ship together; if you rely on it for cookie persistence, upgrade both at once.

Http4s — ResourceService/WebjarService path escape via percent-encoded separators

Http4s's ResourceService and WebjarService decode each path segment and only reject exact ".", "..", or empty segments, so a percent-encoded %2F (or %5C on Windows) smuggles a ../ past the filter and escapes the configured base — classpath and webjar resource disclosure. Check whether either static handler is exposed with a non-root base path.

Netmaker — boolean-based SQL injection in the SQLite DNS-record delete path

Netmaker's SQLite backend builds DELETE statements via string concatenation of user-supplied input in the DELETE /api/dns/{network}/{domain} path, giving an authenticated attacker boolean-based SQL injection. Requires auth, but if you self-host Netmaker's DNS management, patch before rotating any credentials that touch that database.

06:00 ET · Morning Watch

emp3r0r C2 framework — unauthenticated HTTP-polling session creates pre-auth DoS path

emp3r0r's plain-HTTP C2 transport creates and stores a server-side stream for any attacker-supplied session ID before CBOR MsgAuth authentication runs, so unauthenticated POST bodies reach the C2 dispatch path and get queued pre-auth. A flood of bogus polling sessions consumes memory and goroutines and can degrade or crash the server — the same accept-then-authenticate shape worth checking in any HTTP-polling C2 or telemetry service you operate, offensive or defensive. No patched version yet; require auth before allocating a session and cap request-body size if you run emp3r0r infrastructure.

libp2p-quic — remote panic via certificate-expiry race during QUIC handshake

libp2p-quic re-parses a peer's TLS certificate after Quinn reports handshake completion, and that second parse re-runs the wall-clock validity check — so a peer presenting a short-lived cert and withholding the final handshake fragment until it expires turns a successful validation into a panic on the post-handshake `expect()`. Any application exposing a libp2p QUIC listener can be crash-DoS'd by a single well-timed handshake, no malformed packets required. Patched in 0.13.1 — upgrade if you run libp2p-quic listeners on rust-libp2p.

Nezha dashboard — OAuth2 redirect_uri Host-header injection regresses when dashboard_host is unset

Nezha validates OAuth2 redirect_uri against a configured dashboard_host, but when that setting is left empty the check no-ops and the server trusts the client-supplied Host header instead — a regression of a previously-fixed issue. Impact is limited to installs that never set dashboard_host, but it's the kind of default-config gap that survives silently from an old install. Set dashboard_host explicitly and update if you run Nezha's OAuth2 login.