v vanemmerik.ai / SUPPLY-CHAIN
Supply Chain · Watch Tuesday · 25 August 2026 End-of-day synthesis 4 watches · 26 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 — The MCP server ecosystem had its worst disclosure day yet: a dozen-plus agent-tooling projects — PraisonAI, Chainlit, mcp-shell, utcp, qwed-mcp, and more — dropped auth-bypass, SSRF, or RCE advisories within hours of each other.

Fifty new GHSA advisories landed today, and most trace back to one theme: MCP and agent-tooling servers that treat their own tool arguments as trusted config instead of attacker input. PraisonAI's 20-advisory teardown from the forenoon pass got company from Chainlit, mcp-shell, utcp, qwed-mcp/qwed, nextcloud-mcp-server, mcp-contextforge-gateway, genieacs-mcp, browse-mcp, and deepseek-mcp-server — nine more agent-tooling projects with auth-bypass, SSRF, path-traversal, or RCE advisories inside the same window.

Chainlit's unauthenticated command-injection RCE (CVSS 9.8) is the headline of that group, but the two worst bugs of the day aren't MCP-shaped at all: grpc-erlang's unsafe atom decode gives unauthenticated RCE on any reachable BEAM node, and AshAuthentication's OAuth2/OIDC account takeover lets an attacker sign in as any victim who's ever used social login, no prior compromise required. CISA also added Gitea's diffpatch code-injection to KEV with a due date of 2026-08-28 — the one item on this page with a hard federal deadline. The one piece of good news: Chainlit's RCE only reaches deployments that explicitly flip `features.mcp.enabled = true`, off by default since v2.7.0, so most Chainlit installs are already out of the blast radius.

→ Operational priority for the night verify Gitea's patch status against the 2026-08-28 KEV deadline first, then work the MCP list — PraisonAI, mcp-shell, utcp, qwed-mcp, Chainlit-with-MCP-on — treating every tool argument as attacker input until each fix is confirmed in place.

18:00 ET · First Watch

CISA KEV: Gitea code injection via diffpatch API plants an executable Git hook (CVE-2026-60004)

CVE-2026-60004 landed on the KEV catalog today: an attacker with repository write access can send a malicious patch to Gitea's diffpatch API endpoint to plant an executable Git hook and run shell commands as the Gitea service account. Any self-hosted Gitea instance is now a supply-chain choke point — one compromised or malicious contributor account becomes RCE on the server hosting your source. Patch before the 2026-08-28 due date and audit hook directories for anything you didn't put there.

Chainlit: unauthenticated command injection RCE via MCP stdio transport, plus SSRF via SSE/streamable-http

Chainlit's MCP stdio transport takes a user-controlled `fullCommand` string, and `validate_mcp_command()` doesn't stop unauthenticated remote code execution (CVSS 9.8) — a companion advisory covers SSRF via the SSE and streamable-http transports reaching internal network endpoints. Both require `features.mcp.enabled = true`, which has been off by default since v2.7.0, so most deployments are unaffected — but anything that turned MCP on for agent workflows is exposed with zero auth required. Check `.chainlit/config.toml` for that flag and patch immediately if it's set.

grpc (Erlang): unsafe atom decode is RCE, plus 3 more — path override, unbounded body accumulation, decompression bomb

grpc-erlang's Erlpack codec calls `:erlang.binary_to_term/1` on raw gRPC message bodies without the `:safe` option, so any unauthenticated peer that can reach a gRPC endpoint over `application/grpc+erlpack` can exhaust the atom table or, if a decoded fun term reaches a call site, get remote code execution inside the BEAM node. Three more advisories landed in the same package alongside it: path bindings overridable by query string or request body, unbounded request-body accumulation, and unbounded gzip decompression. If you run grpc-erlang, disable Erlpack support or upgrade past all four before exposing the endpoint further.

AshAuthentication: OAuth2/OIDC account takeover via email-based user matching

AshAuthentication's OAuth2/OIDC strategies matched local users by email address instead of the provider's `iss`/`sub` claim pair, so anyone who can register on an accepted OAuth provider using a victim's email — verified or not — signs in as that victim with full account privileges. It's a straightforward account-takeover path on any Elixir/Ash app using social login, and the victim doesn't have to do anything wrong. Patch now and audit for OAuth logins where the local user's email wasn't independently verified.

Five more MCP servers, same failure shapes: contextforge SSTI-RCE, genieacs DNS rebinding, two arbitrary-file-writes, deepseek-mcp-server auth gaps

Five more MCP servers joined today's pile: mcp-contextforge-gateway renders prompt templates through a plain, unsandboxed Jinja2 `Environment()`, so an authenticated template author gets RCE on the gateway host; genieacs-mcp's local Streamable HTTP listener trusts attacker-controlled `Host`/`Origin` headers, so DNS rebinding from a malicious web page reaches it without a browser-supplied secret; consciousness-explorer/sublinear-time-solver's `export_state` and browse-mcp's download/state-path tools both write attacker-controlled paths straight to disk with no traversal checks; and `@arikusi/deepseek-mcp-server` ships a caller-controlled session store plus a self-hosted HTTP endpoint with no auth middleware at all. Same lesson as the rest of today's batch: MCP tool arguments are attacker input, not trusted config, and most of these projects were built as if they weren't.

qwed (standalone package): authenticated RCE via the same unsafe SymPy parse_expr() as qwed-mcp

The standalone `qwed` package — distinct from the `qwed-mcp` critical above — has the same root cause, attacker input straight into SymPy's `parse_expr()`, but only requires a standard user account, freely obtainable through the default-enabled `/auth/signup` endpoint, to get full RCE on the API server. If you run either qwed or qwed-mcp, this is the same fix applied twice; patch both or lock down `parse_expr()`'s `global_dict` in both places.

Trivy: path traversal via a crafted vulnerability database or other downloaded artifact

Trivy uses the `org.opencontainers.image.title` annotation from a fetched OCI artifact's manifest as the destination filename with no validation, so an attacker who can get Trivy to pull a crafted artifact — a poisoned vulnerability database or registry image — can write layer content outside the intended directory. The irony bites: a supply-chain scanner is itself exploitable via a supply-chain-style poisoned artifact. Patch before your next scheduled DB update, and don't point Trivy at untrusted registries until you have.

eml_parser: URL-extraction bypass via HTML entities, plus two header-nesting DoS advisories

eml_parser picked up three advisories today: HTML-entity-encoded URLs slip past its URL extraction, and two separate advisories cover denial-of-service via deeply nested parentheses in email headers — one general, one specifically in Received headers. If you run eml_parser against untrusted inbound mail for phishing or IOC extraction, a hostile message can both evade your URL detection and hang the parser. Upgrade past all three; the header-nesting DoS is cheap to trigger.

phpMyFAQ: GROUP_EDIT privilege escalation, plus authenticated PDF-export path traversal and inactive-FAQ exposure

phpMyFAQ closed out three advisories today: a `GROUP_EDIT` admin can grant permissions they don't hold via `GroupController::updatePermissions` (the headline item), plus authenticated path traversal in PDF export and a public API that leaks inactive FAQ content. The privilege-escalation bug is the one to prioritize — it lets a low-trust admin role climb to full admin rights. Patch and re-audit group permission assignments for anything granted since the bug was introduced.

Plate: media-embed provider metadata bypasses URL sanitization to execute iframe JavaScript

Plate's media-embed renderer trusts serialized `provider`/`sourceUrl` metadata enough to skip its own URL-protocol validation, so a crafted document can claim a known video provider while smuggling a `javascript:` URL as the iframe `src` — executing attacker JS the moment a victim opens the document. Any app built on Plate's registry media-embed component that renders untrusted or shared documents is exposed. Patch, and treat any previously-shared Plate document as untrusted until re-validated.

urllib: cross-origin redirects preserve credential-bearing request headers

urllib's redirect-following preserves credential-bearing headers — `Authorization`, `Cookie`, `Proxy-Authorization`, and custom auth headers like `x-api-key` — verbatim across origin changes, so a redirect to an attacker-controlled or out-of-trust-boundary host walks off with whatever credentials the original request carried. Same shape as the redirect/SSRF-adjacent bugs elsewhere in today's batch — treat any HTTP client that follows redirects by default as a credential-exfiltration path until proven otherwise. Patch, and audit outbound clients that attach long-lived API keys to requests that might get redirected.

Echo: encoded slash (%2F) desync between router and static handler bypasses route-level access control

Echo's router matches routes against the raw encoded path, keeping `%2F` literal, while its static file handler unescapes `%2F` to `/` before resolving filesystem paths — the mismatch lets a crafted URL slip past route-level access controls and read static files the route was supposed to gate. Any Echo service using route middleware to protect a static file mount is affected regardless of what that middleware does right. Patch, then verify your static mounts aren't reachable by a `%2F`-encoded path that dodges the router.

Rounding out the day: icalendar O(2^n) equality DoS, Whistle path traversal, JupyterHub login-log DoS, mediasoup SCTP cookie forgery, Reachy Mini unauthenticated upload

Five smaller items closed out the day: icalendar's `Component.__eq__` does O(2^n) comparison on nested subcomponents, so a sub-kilobyte crafted `.ics` file can hang any app that compares or deduplicates parsed calendar objects; Whistle has a path-traversal in its temp-file download endpoint; JupyterHub's PAM-based login logs unbounded invalid-username input (OAuthenticator users are unaffected); mediasoup's SCTP stack authenticates state cookies with hardcoded bytes instead of a per-instance HMAC, letting an on-path attacker forge a cookie on a PlainTransport with SCTP enabled; and Reachy Mini's sound-upload endpoint takes files with no auth or validation, one link in a documented root-compromise chain. None individually urgent enough to jump the queue, but worth clearing on normal cadence.

12:00 ET · Forenoon Watch

nextcloud-mcp-server: unauthenticated webhook lets anyone wipe another user's vector data

nextcloud-mcp-server's `POST /webhooks/nextcloud` skips auth entirely whenever `WEBHOOK_SECRET` is unset — the shipped default — and takes `user_id` straight from the unauthenticated payload to drive Qdrant deletes. Any deployment with vector sync enabled and no explicit secret is one anonymous POST away from having any user's embeddings wiped or corrupted. Set `WEBHOOK_SECRET` explicitly and verify it's actually enforced before trusting vector search results from this server.

qwed-mcp: unsanitized math-expression tool is RCE via SymPy parse_expr()

qwed-mcp's `verify_math_expression()` passes attacker-controlled strings straight into SymPy's `parse_expr()` without restricting `global_dict`, and `parse_expr()` calls `eval()` with the full builtins available — a math-expression MCP tool that's actually an RCE tool. Any agent that exposes this to untrusted input hands out arbitrary code execution disguised as a calculator. Pin past the patched release or wrap the call with a locked-down `global_dict`/AST allowlist now, not on the normal dependency cadence.

PraisonAI browser-server Origin check bypass — patch bypass of CVE-2026-40289, plus 19 more advisories dropped same-day

PraisonAI's browser-server WebSocket Origin check uses `re.match()` against `chrome-extension://[a-z0-9]{32}` without anchoring the end, so any Origin starting with 32 hex characters plus arbitrary trailing junk still passes — a direct bypass of the already-patched CVE-2026-40289. It landed as part of a coordinated dump of 19 more advisories across PraisonAI and praisonaiagents today (see the two batched entries below); read this as a framework-wide teardown, not an isolated regression. Don't expose PraisonAI's browser server, MCP server, or HTTP API to anything you don't fully trust until the whole batch is patched and verified.

PraisonAI/praisonaiagents: 15 more high-severity advisories — auth bypass on three serve entrypoints, four separate web_crawl SSRF findings, path traversal, arbitrary recipe execution

Fifteen more high-severity GHSAs landed against PraisonAI/praisonaiagents in the same disclosure batch. `--api-key` is silently ignored on three separate `serve` entrypoints (`serve`, `serve agents`, and the async Jobs API has no auth check at all), and the Recipe server and `AgentServer` both declare auth but never enforce it on any route. Four separate advisories cover the same underlying gap in `web_crawl` — SSRF via redirect-following and DNS rebinding, including a `127.0.0.1.nip.io`-style bypass — and there's path traversal via `FileMemory`'s unsanitized `user_id`, workspace-escaping symlinks, and a workflow-include that bypasses the `tools.py` autoload opt-in to run arbitrary recipe code. If you run PraisonAI in production, treat every network-facing surface as unauthenticated-by-default until you've verified all fifteen fixes landed — patching only the headline CVE leaves most of this open.

mcp-shell: "secure mode" allowlist fails three different ways at once

mcp-shell's secure-mode allowlist fails three ways simultaneously: the default Docker config allowlists `/bin/bash` itself, so `command=/bin/bash -c '<anything>'` passes validation outright; the same allowlist includes `git` while the metacharacter filter omits `!`, the prefix Git uses for shell aliases (`alias.NAME=!CMD`); and the from-source deploy path ships with security disabled entirely, so users who skip the Docker config get no restriction at all. Together, neither the documented default nor the recommended secure-mode configuration delivers the restriction it's marketed as providing. Treat any existing mcp-shell deployment as equivalent to unrestricted shell access until all three land.

utcp-http/utcp-gql: OAuth2 tokenUrl trust bypass, SSRF via redirect, and an SSRF fix that missed two plugins

utcp-http (≤ 1.1.3) unconditionally trusts the `tokenUrl` embedded in a remote OpenAPI spec's security scheme, so a victim who registers an attacker-controlled spec and invokes any generated OAuth2 tool has their `client_id`/`client_secret` POSTed to the attacker's token endpoint. Separately, `HttpCommunicationProtocol.call_tool` validates the pre-redirect tool URL but never re-checks where a 302 lands, opening SSRF into internal services and cloud metadata endpoints — and the fix for that exact SSRF class (CVE-2026-44661) never reached the GraphQL or WebSocket plugins, so `utcp-gql` still uses the `startswith` prefix check the original patch was supposed to replace. If you invoke UTCP tools against untrusted OpenAPI specs or GraphQL endpoints, pin past all three patches together — a partial upgrade leaves one of the three paths open.

djust: rejected LiveView mount keeps the WebSocket open, letting an unauthenticated client keep dispatching events

djust's `LiveViewConsumer` sends an unauthorized client a redirect frame when a `login_required` or `on_mount` hook rejects the mount, but never closes the WebSocket or clears the view instance — so the rejected client can keep dispatching event-handler calls over the same socket as if the redirect never happened. That's an authentication bypass on any gated LiveView, not a UX glitch. Patch, then audit for event handlers that assume the mount-time auth check is still valid mid-session.

pickem: unsanitized item text is a terminal escape-sequence injection path

pickem prints item text — labels, descriptions, group and meta fields — straight to the terminal with incomplete control-character sanitization: `chrome.row` only strips ANSI from the active row, and even that misses bare C0 controls. Item text is routinely attacker-influenced (git branch names, PR titles, and similar), so this is a live terminal escape-sequence injection path for anyone piping untrusted strings into pickem. Upgrade past the fix, and treat any CLI tool that renders external strings without sanitizing C0/ANSI as suspect.

PraisonAI/praisonaiagents: 4 medium items round out today's batch — webhook SSRF, unguarded file rewrite, unbounded session growth

Four medium-severity items close out the PraisonAI batch: a webhook SSRF via DNS-rebinding bypass in `validate_webhook_url()`, an `ast_grep_rewrite` tool that rewrites arbitrary files without the `@require_approval` gate every sibling mutation tool enforces, an MCP HTTP Stream transport origin-validation bypass enabling browser-mediated unauthenticated tool execution, and an MCP HTTP server whose session TTL is never enforced, letting unauthenticated sessions accumulate until memory runs out. None of these are RCE on their own, but they're more evidence the framework's security model was aspirational rather than enforced — fold them into the same PraisonAI remediation pass as the critical and high items above.

06:00 ET · Morning Watch

CISA KEV backfill: Arista VeloCloud Orchestrator OS command injection (CVE-2026-16812)

CVE-2026-16812 hit the KEV catalog on 2026-07-27 — a month-old add this pipeline missed until today's backfill sweep — covering an OS command-injection flaw in Arista VeloCloud Orchestrator On-Prem that gives a remote attacker access to privileged internal functionality and can compromise the confidentiality, integrity, and availability of the orchestrator and everything it manages. The due date (07-30) is three weeks gone, so treat any unpatched on-prem VCO as presumed-touched until proven otherwise. Patch per Arista's advisory and pull orchestrator logs back to late July for exploitation indicators.

postgres-protocol: malformed hstore value panics the client (DoS)

postgres-protocol panics decoding a binary hstore value that carries an invalid internal length field, letting a malicious or MITM'd Postgres server crash a connecting client outright. Same shape as the SCRAM and short-DataRow panics disclosed in the same crate family yesterday — only exposed if your client ever talks to an untrusted or interceptable Postgres endpoint. Upgrade past 0.6.12, the same fix that closes the other two.

CISA KEV backfill: FortiOS symlink-persistence patch bypass (CVE-2025-68686)

Also caught in today's backfill: CVE-2025-68686, a FortiOS flaw letting an attacker who already has filesystem-level footing bypass the patch for the symbolic-link persistence mechanism seen in earlier FortiOS compromises, via crafted HTTP requests. It's a persistence-technique fix, not a new way in — it only matters on a box already popped through something else. If you run FortiOS and haven't re-checked for the original symlink-persistence indicators, this KEV add (three weeks old before we caught it) is the prompt to do it now.

netfoil: unvalidated DoH response data written directly to logs

netfoil writes unverified ALPN bytes and the raw single-byte response code from a DNS-over-HTTPS server straight to its logs without sanitizing them, which can pollute logs with arbitrary byte sequences and waste memory. Low severity, no exploitation path past log noise — clear it on your normal dependency cadence.