v vanemmerik.ai / SUPPLY-CHAIN
Supply Chain · Watch Thursday · 30 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 — A default-config Rails RCE and a six-CVE meltdown in an AI workflow framework landed the same day Amazon confirmed North Korea authored last year's record npm hijack.

Two framework-level critical vulnerabilities defined today's disclosures, landing hours apart. Rails' Active Storage ships a default-config path to unauthenticated arbitrary file read — and likely RCE — through libvips's unfuzzed image operations, while flyto-core's coordinated six-CVE batch confirmed its SSRF guard is a per-module suggestion, not a boundary.

The Rails bug (CVE-2026-66066) hits any app on the vips variant processor — the default since Rails 7.0 — that accepts image uploads from untrusted users, letting an attacker read secret_key_base and every credential the process can see. flyto-core's cluster (two CVSS-9+ criticals: arbitrary file write and unauthenticated runner-secret exfiltration) tells the same trust-boundary story, echoed by dssrf's own SSRF-protection library getting bypassed by the identical @-symbol trick its last patch was meant to fix, and by smaller coordinated hardening batches in MCP's Ruby SDK and OliveTin. Amazon separately confirmed North Korea's Sapphire Sleet authored September's debug/chalk npm hijack, ten months on — and Socket and Phylum flagged zero new malicious packages today, so this is a disclosure-heavy day rather than an active-exploitation one.

→ Operational priority for the night patch activestorage and libvips past 8.13 and rotate every secret the Rails process can read first, then lock down flyto-core's verification service and re-test any SSRF-guard library you depend on against the userinfo-prefix bypass.

18:00 ET · First Watch

Active Storage variant processing allows unauthenticated arbitrary file read en route to RCE

Rails' Active Storage passes untrusted uploads to libvips's ‘unfuzzed’ loaders and savers without disabling them, so an unauthenticated attacker who uploads a crafted file and triggers variant generation can read arbitrary files off the server — including the process environment, which typically holds secret_key_base and credentials for every external system the app talks to. This is default-configuration exposure: variant_processor: :vips has been the default since Rails 7.0, and the only other precondition is allowing image uploads from untrusted users. Upgrade activestorage and libvips past 8.13, then rotate secret_key_base, the master key, and every credential the app process could read — the upgrade closes the hole but doesn't undo a secret that already leaked.

AWS Amplify Studio's component import lets an authenticated user run arbitrary JS during build

amplify-codegen-ui's property-binding expression generator doesn't validate a component schema's properties before converting them into JS expressions, so an authenticated Studio user who can create or import a component — including via the CLI create-component path — can get arbitrary JavaScript executed during component rendering and the build process. That's a build-pipeline compromise vector on any multi-author Amplify Studio project: a malicious or compromised collaborator's component becomes code execution in your build, not just their own session. Upgrade past 2.20.4 and audit any recently-imported component schemas from collaborators you don't fully trust.

dssrf's own @-symbol fix reopens the SSRF hole it was patched to close

dssrf strips '@' from a URL string before parsing it, which corrupts the userinfo/host boundary so http://[email protected]/ resolves to an unrecognized hostname and sails past every internal-IP check — the exact bypass the library's prior patch (GHSA-8p33) was supposed to close. Any HTTP client trusting is_url_safe() as its SSRF gate is exposed to loopback, RFC1918, and cloud-metadata targets via a one-character trick, the same SSRF-guard-that-doesn't-guard shape as today's flyto-core cluster below. Upgrade to 1.0.4, and don't treat a dedicated SSRF library as correct without testing the userinfo-prefix bypass yourself.

msgpack's Buffer#clear leaves a stale memory cursor, letting two buffers alias the same page

MessagePack::Buffer#clear frees a chunk's memory page back to a shared pool but doesn't reset the buffer's internal rmem cursor, so the next write on that buffer — and a second buffer's next allocation — can land on the same physical page, disclosing one buffer's bytes to the other. Real-world severity is low-to-medium: it only fires under a clear-then-reuse lifecycle via the Buffer API directly, not plain unpack() calls, but it's worth knowing if you pool MessagePack buffers across requests or tenants.

DPRK-linked malvertising delivers crypto-stealing malware via fake macOS update screens

A new iteration of the Contagious Interview campaign redirects victims to fake full-screen macOS 'update' sequences that stealthily deliver crypto-stealing malware, attributed to North Korea-linked actors. Not a package-registry compromise, but it's the same actor ecosystem behind today's Sapphire Sleet attribution on the debug/chalk npm hijack — DPRK crews are running social-engineering and malvertising lures in parallel with supply-chain compromise as interchangeable initial-access methods. If you support developer-facing macOS fleets, treat unexpected full-screen 'update required' prompts as suspicious by default.

12:00 ET · Forenoon Watch

Flyto2 Core's image.download writes attacker-hosted bytes to any absolute path on the host

Flyto2 Core's image.download module checks that a write path stays inside a base directory, but the base directory (output_dir) is itself a caller-supplied parameter, so setting it to '/' makes the containment check pass for any absolute target — attacker-hosted bytes land wherever the process can write. CVSS 10 on a workflow-automation framework: arbitrary file write from a public HTTP fetch is one step from RCE via cron files, SSH authorized_keys, or a loaded config file. Patch immediately if you run flyto-core, and treat any exposed file-writing module as full host filesystem access until you do.

Flyto2 Core's standalone verification service leaks its internal runner secret to any caller

The standalone flyto-verification service listens on 0.0.0.0:8344 with no authentication on POST /run, and unconditionally attaches the internal X-Internal-Key runner secret to whatever callback_url the request body supplies — a field that bypasses the service's own target allowlist entirely. An unauthenticated attacker gets both SSRF into internal/metadata endpoints and the secret needed to forge authenticated callbacks to the real engine. Firewall this service off the network today; there's no auth layer to patch around.

Flyto2 Core's guarded HTTP modules follow redirects straight into internal address space

flyto-core's guarded HTTP modules (http.get/request/batch) validate only the initial URL, then let aiohttp follow redirects with no per-hop revalidation, so a 302 from an allowlisted public host to an internal address (cloud metadata, loopback) sails straight through. This is the fourth SSRF-shaped flyto-core bug published in today's batch alongside the two criticals above. Set allow_redirects=False or revalidate every hop until patched.

A dozen-plus Flyto2 Core HTTP modules carry an SSRF-protected tag but never call the actual guard

A dozen-plus flyto-core modules — HTTP get/post, GraphQL, Slack/Discord/Teams notifications, browser proxy rotation, the LLM base_url branch — carry an ssrf_protected metadata tag but never actually call the project's SSRF guard, unlike sibling modules that do. Because the guard is per-module rather than a global egress interceptor, an authenticated workflow author can point any of these at 169.254.169.254 or an internal host and read the response. Audit which flyto-core modules are wired into your workflows; the metadata tag is not a control.

Flyto2 Core's llm.chat sends the operator's provider API key to a caller-controlled endpoint

llm.chat reads the operator's OpenAI/Anthropic API key from the environment and sends it as a Bearer token to base_url, a caller-controlled parameter that only passes an SSRF check, not a destination allowlist — pointing base_url at an attacker's server hands over the key. The same env-key-plus-caller-endpoint pattern exists in ai.model, llm.agent, and vector.connector. If workflow authors can set base_url in your deployment, rotate the provider keys now.

${env.VAR} template interpolation reads any host secret despite env.get being denylisted

flyto-core denylists the env.get module specifically because it reads arbitrary host secrets — but the workflow engine's ${env.VAR} variable interpolation resolves any environment variable with no allowlist and no policy check, since it runs before module-policy enforcement kicks in. The exact capability the denylist exists to block is reachable through template syntax instead. Six flyto-core CVEs in one disclosure batch is a pattern, not a coincidence — treat the framework's trust boundary model as broken until a coordinated fix lands, not just these six symptoms.

MCP Ruby SDK's Streamable/SSE transport never checks that a session ID belongs to its caller

The Ruby MCP SDK's Streamable/SSE HTTP transport never validates that a session ID belongs to the caller presenting it, so anyone who obtains a victim's session ID — via logs, network capture, or a leaked referrer — can execute tools under that session with no visible sign to the victim. It's a silent takeover: the victim's own session keeps working normally while an attacker rides along on it. If you're running MCP servers on the Ruby SDK, treat this alongside the DoS advisories below as one bad week for the transport layer and patch once a fixed release lands.

MCP Ruby SDK's StreamableHTTPTransport allocates gigabytes on a single oversized JSON-RPC POST

StreamableHTTPTransport reads an entire JSON-RPC POST body into memory with no size limit and no Content-Length pre-check before parsing, so a single oversized request can force gigabytes of allocation on any Ruby MCP server exposing this transport — unauthenticated, trivial DoS. Put a body-size limit in front of any MCP server on this SDK (reverse proxy or Rack middleware) until the gem itself enforces one.

OliveTin's OAuth2 login handler grows an unbounded in-memory map on every login attempt

OliveTin's OAuth2 login handler stores every /oauth/login attempt in an in-memory map that's never expired or capped, so an unauthenticated attacker can flood the endpoint to exhaust server memory — a distinct bug from the already-patched concurrent-map-write panic (CVE-2026-28789), same map, different failure mode. If you self-host OliveTin with OAuth2 login enabled, rate-limit or front /oauth/login until a release adds state expiry.

MCP Ruby SDK: unbounded stdio line buffer, unbounded session retention, and no DNS-rebinding protection

Three more medium-severity Ruby MCP SDK issues round out today's batch: stdio transports buffer an unbounded line with IO#gets until the OOM killer intervenes — the same vulnerability class already fixed in the Kotlin, TypeScript, and Python MCP SDKs — sessions are never expired so a flood of initialize requests exhausts memory (GHSA-52jp-gj8w-j6xh), and the Streamable HTTP transport has no Host/Origin allowlist, leaving local MCP servers open to DNS-rebinding from any browser tab a victim visits (GHSA-rjr6-rcgv-9m7m). None need attacker network access beyond a victim's browser or a loopback port; harden session limits, buffer caps, and Origin checks in front of any Ruby MCP deployment.

OliveTin's shell-argument safety check forgot to blocklist regex:-typed arguments

OliveTin's shell-argument safety check blocklists unsafe argument types but omits regex:-typed ones, added later via a separate code path — any Shell-mode action using a regex: argument bypasses shell escaping entirely and gets interpolated raw into sh -c, and even restrictive-looking regex patterns are bypassable via POSIX command substitution. A second, unrelated bug in the same release lets StartActionAndWait return full action output even when the caller's ACL denies log access (GHSA-jm28-2wcr-qf3h). Check both if you run OliveTin for on-call automation.

linuxfabrik-lib's fetch() leaks non-standard credential headers to redirect targets

linuxfabrik-lib's fetch() helper follows redirects and relies on httpx to strip Authorization/Cookie cross-origin — but every other credential header, like Redfish's X-Auth-Token or a bespoke API key, isn't stripped, so a malicious or compromised redirect target receives the token. Any monitoring plugin authenticating to a redirect-capable host is exposed; audit custom header usage in Redfish/BMC plugins built on this library.

State-sponsored campaign compromises Korean sites to exploit AnySign4PC and drop backdoors silently

South Korean authorities and four security firms disclosed a state-sponsored watering-hole campaign that compromised trusted domestic sites to exploit a vulnerable version of the locally-installed AnySign4PC financial-security software, dropping SIGNBT or COPPERHEDGE backdoors without any user prompt. It's not a package-registry compromise, but the shape rhymes: a trusted distribution channel and a client-side security tool as the exploited surface. If AnySign4PC is anywhere in your environment, confirm it's patched past the exploited version.

Analog Devices discloses a breach, says chip operations are unaffected

Analog Devices disclosed that an unauthorized party accessed internal systems and exfiltrated files, with the company saying chip operations are unaffected. Semiconductor vendors sit upstream of a lot of embedded and IoT supply chains; nothing actionable yet, but worth a watch for whether design files, firmware signing material, or customer data surface later.

Russian state actor Void Blizzard exploits an Exchange OWA zero-day for long-term mailbox access

Russian state actor Laundry Bear (aka Void Blizzard) is exploiting an Exchange Outlook Web Access zero-day to deliver a backdoor called OWAReaper for long-term mailbox access. Not a supply-chain compromise, but the same actor class and persistence goal as the campaigns this page usually tracks — if you run on-prem Exchange OWA, prioritize patching once Microsoft ships a fix and hunt for OWAReaper indicators in the meantime.

06:00 ET · Morning Watch

proot-distro install lets a malicious tar archive symlink-escape to write files on the host

proot-distro's plain-tar install path (`_extract_plain_tar()`) resolves symlinks in the archive without confirming targets stay inside the container root, so a malicious rootfs tarball can write files to the real host filesystem during `proot-distro install` — CVSS 8.2, CWE-61. This is the install-time sibling of yesterday's restore-flow bypass (GHSA-7h3g); both boil down to proot-distro trusting archive contents it shouldn't. Treat any rootfs tarball you didn't build yourself as untrusted and patch past 5.1.4 before extracting.

netfoil's block response resolves to localhost instead of dropping traffic

netfoil's DNS blocklist returns `0.0.0.0` instead of NXDOMAIN for blocked domains, and on Linux — netfoil's target platform — `0.0.0.0` resolves to localhost rather than being dropped, so blocked traffic gets redirected to whatever's listening on the local host instead of failing closed. Impact depends on what's bound to loopback and your firewall rules, but a DNS-based blocklist that redirects to localhost is the wrong failure mode for a security control. Upgrade past 0.4.0 and audit anything listening on loopback on hosts running netfoil.

Amazon attributes the debug/chalk npm hijack to North Korea's Sapphire Sleet, ten months later

Amazon has formally attributed last September's hijack of the npm packages debug and chalk — combined weekly downloads over 2 billion — to North Korea's Sapphire Sleet group, ten months after the incident was publicly understood as opportunistic crypto-wallet theft via a phished maintainer account. The attribution matters more than the technical details: a state-linked actor running the same maintainer-phishing playbook as financially-motivated crews means npm-ecosystem defenses like 2FA enforcement and publish-time review are now a nation-state control, not just anti-fraud hygiene. Worth revisiting whether your dependency-pinning and SBOM tooling would have caught the phishing vector or the wallet-drain payload, since the same TTP will resurface under other cover.

Easy!Appointments leaks full customer PII on the unauthenticated booking-reschedule page

Easy!Appointments' booking-reschedule page embeds the entire customer record — every column of the ea_users row — as inline JavaScript, reachable by anyone holding the 12-character appointment_hash that already appears in plaintext in confirmation emails and calendar links. No authentication is required, and the hash isn't treated as a secret by design, so this is a straightforward PII leak baked into how the reschedule flow shares links. Patch is pending upstream; in the meantime, treat reschedule links as bearer tokens and don't forward them outside the customer relationship.

OpenTelemetry JDBC auto-instrumentation logs cleartext database passwords to traces

OpenTelemetry's JDBC auto-instrumentation fails to strip double-quoted passwords from SQL CONNECT statements before logging them, so cleartext database credentials can land in trace span attributes and ship straight to your observability backend. CVSS 6.5 — the risk here is less about exploitation and more about silent credential sprawl into logging/tracing systems that often have broader read access than the database itself. Upgrade past 2.28.0-alpha and grep existing trace stores for CONNECT statements if you've been running an older agent.

OpenTelemetry Java agent's RMI instrumentation is vulnerable to memory-exhaustion DoS

The OpenTelemetry Java agent's RMI context-propagation reader caps the number of entries it accepts but not their aggregate size, so an oversized payload sent to a network-reachable RMI endpoint on an instrumented JVM can force excessive memory allocation — CWE-400. This only matters if RMI instrumentation is enabled and the endpoint is network-reachable; upgrade past 2.27.0 if that's you, otherwise it's a non-issue.

mathlive's \text{} and \mbox{} commands reflect unescaped HTML, reopening XSS the 0.104.0 patch missed

mathlive's earlier 0.104.0 XSS patch escaped attribute-bearing LaTeX constructs but missed text-content reflection: \text{} and \mbox{} bodies get written raw into both the HTML markup and MathML output. CVSS 6.3 — any app rendering user-supplied LaTeX with mathlive (equation editors, math-heavy forms) is exposed to stored or reflected XSS through those two commands specifically. Upgrade past 0.109.2; treat this as a second pass on the same escaping bug, not a new class of issue.

matrix-commander still depends on Olm versions carrying 2022–2024 CVEs

matrix-commander's Python variant still depends on libolm (Olm), which carries multiple already-disclosed 2022–2024 CVEs — AES timing side-channels, Ed25519 signature malleability, and a base64-decode timing leak — that upstream Matrix SDKs patched years ago but this dependency chain never picked up. It's a stale-transitive-dependency advisory rather than a new vulnerability: the fixes already exist, matrix-commander just hasn't moved off the vulnerable Olm path. If you run matrix-commander, confirm which crypto backend it actually uses and move to a patched Matrix SDK/libolm.

ActiveRecord::Tenanted's DiskService#path_for is vulnerable to path traversal via untrusted blob keys

ActiveRecord::Tenanted's override of Active Storage's DiskService#path_for doesn't confirm the resolved path stays inside the storage root, so a blob key containing ../ sequences can read, write, or delete arbitrary files — but only if the app passes untrusted input as blob keys, which isn't the documented usage. Low severity given that precondition; upgrade past 0.7.0 and confirm blob keys in your app are never user-supplied.

Easy!Appointments' booking-disabled message renders unescaped, enabling admin-planted stored XSS

An authenticated Easy!Appointments admin can store HTML/JS in the 'booking disabled' message field, which renders unescaped on the public booking page — stored XSS, but it requires an admin account to plant and only fires for other visitors, not the admin's own session. CVSS 2.6; low priority unless you have untrusted admins on the instance.

Easy!Appointments lets any backend user rebind a peer provider's Google Calendar sync

Easy!Appointments' Google OAuth callback saves an issued token against whatever provider_id was stashed in session without checking the caller owns that provider, so any backend user — admin, provider, or secretary — can rebind a peer's Google Calendar sync to their own account and start receiving that peer's appointment and customer data as calendar invites. CVSS 3.1, requires an existing backend login; still worth an audit if several providers share one instance.

Easy!Appointments' appointment endpoints skip provider-ownership checks, enabling cross-provider injection

The direct-mutation endpoints appointments/store and appointments/update check generic permissions but never verify the submitted id_users_provider belongs to the caller, so an authenticated provider can inject or reassign appointments into a peer's schedule — the same isolation boundary the search endpoint correctly enforces, just missed on the write path. CVSS 3.3; low priority unless providers on the instance don't trust each other.

Easy!Appointments' CalDAV connection test is vulnerable to SSRF into the deployment's internal network

Easy!Appointments' CalDAV connection test hands the request's caldav_url to a Guzzle REPORT call without validating scheme or host, so a backend user can reach loopback, RFC1918, and link-local addresses on the deployment's network — semi-blind SSRF, since the error response leaks the upstream status code and a snippet of the body. CVSS 2.7 given the auth precondition, but worth knowing if this instance sits near sensitive internal services.