v vanemmerik.ai / SUPPLY-CHAIN
Supply Chain · Watch Friday · 17 July 2026 End-of-day synthesis 4 watches · 51 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 blockchain-controlled npm campaign returns as ViteVenom, while five unrelated projects each shipped a patch that admitted its first fix missed the vulnerability's sibling path.

The day opened with the FortiSandbox KEV twin and a wave of first-thing disclosures — ArcadeDB's five-advisory authorization batch, Envoy Gateway's six-advisory 1.8.0 pre-release wave, and the first two MCP Python SDK bugs — then went quiet through the forenoon with just a pair of Contagious Interview and ACR Stealer writeups. Tonight's fetch turned up the day's one confirmed active campaign, plus a fresh batch of 26 GHSA disclosures published almost entirely within the last two hours.

ViteVenom, Checkmarx's name for seven blockchain-C2-controlled npm packages hitting Vite tooling, is an expansion of the ChainVeil campaign this watch has tracked since earlier this year — the shift to Tron-based C2 is built to outlast registry takedowns, since there's no domain to seize. Running alongside it is a pattern that showed up five separate times today across otherwise-unrelated projects: Skipper, ArcadeDB, Pheditor, CloudTAK, and Flask-Reuploaded each shipped an advisory admitting their first fix covered one code path and missed a sibling one. And the MCP ecosystem logged its fifth advisory of the day — mcp-memory-keeper and meta-ads-mcp joining this morning's MCP Python SDK pair — the same shape of auth-boundary gap recurring in a tooling category barely a year old.

→ Operational priority for the night audit dependencies against the ViteVenom package list and block Tron RPC egress from build environments first; if you run Skipper, CloudTAK, ArcadeDB, Pheditor, or Flask-Reuploaded, don't assume yesterday's patch closed the door — check for the sibling-path advisory before moving on.

18:00 ET · First Watch

Checkmarx uncovers ViteVenom: seven malicious npm packages hit Vite tooling with blockchain-backed C2

Checkmarx flagged seven malicious npm packages targeting Vite build tooling — dubbed ViteVenom — that use a four-tier blockchain command-and-control layer spanning Tron and other chains to fetch second-stage payloads and drop a RAT. It's an expansion of the ChainVeil campaign this watch has tracked moving through developer tooling all year, and blockchain-backed C2 is specifically built to survive registry takedowns and DNS sinkholing since there's no domain to seize. Audit any recent Vite-adjacent dependency additions against Checkmarx's package list, and block outbound calls to Tron RPC endpoints from build environments that shouldn't need them.

Skipper: incomplete fix for CVE-2026-50197 — an oversized body still bypasses OPA deny-on-presence policies

Skipper's fix for CVE-2026-50197 only handled the chunked/no-content-length case; when a request declares a Content-Length larger than the configured max, the body-extraction path still hands OPA an empty parsed_body while the full oversized payload reaches upstream, so deny-on-presence Rego policies fail open. First of three Skipper advisories filed within minutes of each other this evening. Rewrite deny-on-presence policies to check input.attributes.request.http.truncated_body explicitly rather than trusting field-presence logic, and upgrade to 0.27.26.

CloudTAK: authenticated full-read SSRF in the /api/esri* routes — no IP-classification guard

Six routes in CloudTAK's ESRI helper family accept an attacker-controlled URL and fetch it with no IP/DNS classification — the only check, sniff(), pattern-matches the URL path, never the host — so any authenticated user, not just admins, can reach cloud instance metadata or loopback services and get the full response body back. The project already has an isSafeUrl guard wired into its basemap, task, and video-service code paths; it was simply never applied to the ESRI routes. Patch to 13.10.0, or front the ESRI endpoints with an egress proxy that blocks RFC 1918 and 169.254.169.254 in the meantime.

Flask-Reuploaded: case-folding lets a filename slip past the extension denylist — incomplete fix for CVE-2026-27641

The extension denylist in Flask-Reuploaded's name-override path is case-sensitive, so a filename like exe.PHP slips past it — an incomplete-fix variant of last year's CVE-2026-27641, same root cause of denylisting instead of allowlisting. If you patched the earlier CVE and considered it closed, it isn't; switch to an extension allowlist rather than adding another case to the denylist.

Prompty's TypeScript loader executes JavaScript embedded in a prompt file's frontmatter

Prompty's TypeScript loader executes JavaScript embedded in a prompt file's frontmatter, so loading a .prompty file from an untrusted source is equivalent to running arbitrary code — a prompt template shouldn't be a code-execution surface, but here it is. Treat any .prompty file from outside your org the same as an untrusted script; see the companion file-read advisory below.

Prompty: arbitrary file read via file-reference expansion, across all four language bindings

Companion advisory to the frontmatter RCE above: Prompty's file-reference expansion resolves paths without restricting them to the template directory, so a crafted reference reads arbitrary files off the host. Affects the pip, npm, rust, and .NET builds alike — patch all language bindings you've deployed, not just one.

Gitea: insufficient permission checks leak private-repo information through Composer package source links

Gitea's Composer package registry doesn't fully enforce per-repository permission checks on package source links, letting a user without read access to a private repo infer information about it through Composer's package metadata. If you self-host Gitea as a private Composer registry, audit access logs for unexpected Composer metadata requests against private packages.

meta-ads-mcp: X-Pipeboard-Token header auth reuses the operator's own Meta access token

meta-ads-mcp's X-Pipeboard-Token header authentication reuses the operator's own Meta access token as the bearer credential — any client that can reach the MCP server inherits the operator's full Meta Ads account access, not a scoped session. Third MCP-ecosystem advisory today; MCP servers keep shipping the same shape of bug, where token/session isolation between operator and caller was never actually enforced. See the companion SSRF below in the same package.

meta-ads-mcp: SSRF in upload_ad_image via an unrestricted image_url fetch

Same package as the token-reuse advisory above, different route: upload_ad_image fetches an unrestricted image_url with no destination validation, so a caller can point the server at internal infrastructure. Patch both meta-ads-mcp advisories together — they share the same underlying trust assumption that anything reaching the MCP server is the operator.

Python sh library's _uid privilege drop leaves supplementary groups intact

The Python sh library's _uid parameter drops the effective UID but doesn't drop supplementary groups, so a process that thinks it de-privileged itself retains group memberships — and any group-writable resource that comes with them — from its original privileged context. If you use sh to de-privilege a subprocess before running untrusted input, verify group membership separately; UID alone isn't the full privilege boundary.

AWS-JDBC Wrapper: connection-pooling edge case lets a lower-privileged role reuse a higher-privileged Aurora PostgreSQL connection

The AWS JDBC Driver wrapper mishandles a connection-pooling edge case against Aurora PostgreSQL that lets a lower-privileged database role reuse connection state associated with a higher-privileged one. Audit connection-pool configuration if you run the AWS JDBC wrapper against Aurora PostgreSQL with role-based access separation, and patch before relying on database-level privilege boundaries in a shared-pool setup.

vLLM: ReDoS via structured_outputs.regex compiled without a timeout

vLLM compiles user-supplied structured_outputs.regex constraints via xgrammar and outlines without a compilation timeout, so a crafted regex can hang the compiler — classic ReDoS, against an LLM inference server's request path rather than a web app. If you expose structured-output/regex-constrained generation to untrusted prompts, cap compilation time or validate regex complexity before compiling.

vLLM: remote DoS via invalid recovered-token reinjection

A malformed recovered token in vLLM's decoding path gets reinjected into generation state without validation, crashing the server process — a remote, unauthenticated DoS against any vLLM deployment accepting untrusted completion requests. Second of four vLLM advisories tonight, all DoS-shaped rather than RCE; patch on the normal cycle unless you're internet-facing without a request-validation layer in front.

Skipper's routesrv control plane serves cluster route topology and Redis/Valkey shard addresses with zero authentication

Skipper's routesrv component serves full cluster route topology — backend URLs, filter chains, OAuth/OIDC callback paths — and cache-cluster shard addresses over plain HTTP with no authentication, reachable by any pod that can resolve its predictable in-cluster DNS name. Second Skipper advisory tonight; a compromised pod with namespace-scoped RBAC can read cluster-wide routing data that Kubernetes RBAC was supposed to keep it from seeing. Add a NetworkPolicy restricting ingress to routesrv, or require auth via -route-server-filters.

Skipper's admission webhook reads request bodies with no size cap

Skipper's Kubernetes admission webhook reads incoming request bodies without a length limit, so a large enough object create/update can exhaust the controller's memory. Third and least severe of tonight's Skipper batch — a DoS, not a bypass — but worth patching in the same maintenance window as the other two since it's the same component.

CloudTAK: the same missing SSRF guard also left PUT /api/basemap unprotected

Same missing-isSafeUrl root cause as the ESRI advisory above, this time in the basemap import path — another route that should have inherited the guard during the earlier SafeURL hardening pass and didn't. If you're patching CloudTAK for the ESRI SSRF, grep for other fetch() calls on user-supplied URLs before calling it closed; this is the second miss from the same rollout.

PocketSphinx: buffer overflows loading corrupted or malicious language/acoustic model files

PocketSphinx's language-model loader skips boundary checks parsing ARPA/DMP/binary model headers, and the decades-old acoustic-model loader leans on unbounded sscanf — both can stack- or heap-overflow on a corrupted or malicious model file, including one dropped into a world-writable POCKETSPHINX_PATH directory. Upgrade to 5.1.1; there's no patch for 5prealpha, so keep that directory locked down if you can't migrate yet.

AngleSharp: mutation XSS via the annotation-xml MathML integration point

AngleSharp's HTML5 parser lets markup smuggle content through the annotation-xml MathML integration point in a way that reads as inert during sanitization but executes after a round-trip through the DOM — a classic mutation-XSS bypass. Relevant to anything using AngleSharp for server-side sanitization of user-supplied HTML; re-test your sanitizer allowlist against this integration point specifically.

PRoot-Distro: path traversal in proot-distro copy writes outside the container rootfs

proot-distro copy doesn't validate destination paths, letting a crafted archive or copy target write files outside the intended container rootfs — arbitrary read/write and persistent code execution on the host from inside what's supposed to be a sandboxed distro install. Audit any automated proot-distro provisioning that pulls distro images from untrusted sources.

ExifReader throws an uncaught RangeError on a truncated HEIC/AVIF box

ExifReader's HEIC/AVIF ISO-BMFF box parser throws an uncaught RangeError on a truncated box instead of failing gracefully — an unhandled-exception DoS against anything running ExifReader over user-uploaded images without its own try/catch boundary. Wrap ExifReader calls if you haven't already.

mcp-memory-keeper: unvalidated filePath in context_import reads arbitrary local files

mcp-memory-keeper's context_import tool takes a filePath parameter and reads it without confirming it stays inside the intended directory — an MCP server built to persist agent context becomes an arbitrary local file reader for anything with tool access. Fourth MCP-ecosystem advisory across today's watch, after this morning's MCP Python SDK session-hijack and task-isolation bugs and this evening's meta-ads-mcp pair below; validate filePath against an allowlisted root before running memory-keeper against untrusted input.

Formie: low-privileged Craft CMS control-panel users can modify plugin-wide settings

Formie's administrative settings endpoint checks for general control-panel access but not the specific permission the settings page implies, so low-privileged CP users can modify plugin-wide configuration. Restrict Formie settings access to admin-tier CP users until patched.

plone.restapi: stored XSS via a spoofed rich-text MIME type

plone.restapi accepts a spoofed MIME type on rich-text field input, storing content the sanitizer thinks is plain text but a browser renders as HTML — the sanitizer never runs because the content type it checks is the wrong one. Companion advisory below hits plone.app.textfield with the identical bug; patch both, since one alone doesn't close the path if the other is still in your dependency tree.

plone.app.textfield: the same spoofed-MIME-type stored XSS as plone.restapi

Same root cause as GHSA-8rqh-vxpr-x77p above, this time in plone.app.textfield: a spoofed MIME type on rich-text input bypasses sanitization and stores content that renders as HTML. Patch both packages in the same pass.

vLLM: speech-to-text upload size limit is enforced after the full file is already buffered

vLLM enforces its speech-to-text upload size limit after reading the full UploadFile into memory rather than during the stream, so the limit doesn't actually bound memory use — a large audio upload gets fully buffered before it's rejected. Third of four vLLM advisories tonight; the audio/speech-to-text path is where most of them cluster.

vLLM: a multi-channel audio downmixing differential lets hidden input bypass moderation

A processing differential between how vLLM downmixes multi-channel audio for moderation checks versus for actual inference lets a crafted multi-channel file pass moderation as one signal while the model processes a different one — a hidden-input bypass for anything gating on audio moderation. Fourth of tonight's vLLM batch; if you rely on vLLM's built-in audio moderation as a safety boundary, treat it as bypassable until patched.

oapi-codegen: a crafted OpenAPI Server Description escapes the generated Go doc comment and injects code

oapi-codegen writes the OpenAPI spec's Server Description field verbatim into a Go doc comment in generated code, and a crafted description can break out of the comment and inject executable Go — a code-generation supply-chain path where the malicious input is the spec you're generating from, not a dependency. Relevant if you codegen from OpenAPI specs you don't fully trust, e.g. a third party's published spec.

12:00 ET · Forenoon Watch

North Korea's Contagious Interview cluster hides OtterCookie-aligned payloads inside SVG flag images

The fake-job/coding-test lure now hides a four-stage OTTERCOOKIE-aligned payload — browser and crypto-wallet stealer, file stealer, plus later stages — inside SVG flag images rather than a malicious npm postinstall script, so package-registry scanners never see it. Same Contagious Interview cluster this watch has tracked moving through developer tooling all year; the shift to image steganography is a response to scanners getting better at catching script-based droppers. If you run take-home coding challenges from unverified recruiters, treat any bundled image or asset file as untrusted before opening it.

ACR Stealer pairs ClickFix social engineering with M365/OneDrive/SharePoint token theft

ACR Stealer, an infostealer active since 2024, is being delivered via ClickFix — the copy-paste-into-Run-box lure — and once on a host it pulls saved browser passwords, live session tokens, PDFs, and Microsoft 365 documents including synced OneDrive/SharePoint files. Microsoft's Defender Experts team detailed two separate delivery chains this week; the session-token theft matters more than the password theft since it survives an MFA prompt. Not a package-registry compromise, but the same class of credential harvesting that turns into a maintainer-account takeover if it lands on the wrong laptop — user education on ClickFix (never paste anything into Win+R) is still the best control.

06:00 ET · Morning Watch

CISA's July 16 FortiSandbox KEV add was actually two CVEs, not one

Yesterday's watch flagged CVE-2026-25089 as a same-day CISA KEV add for FortiSandbox OS command injection; CVE-2026-39808 is its twin, catalogued the same day and covering the same unauthenticated command-injection class via crafted HTTP requests. Same product, same BOD 26-04 deadline of 2026-07-19. If you patched FortiSandbox for 25089 yesterday, confirm the fix train also closes 39808 rather than assuming one CVE closed the ticket.

ArcadeDB: read-only reader role escalates to arbitrary host file read via the JS-scripting command endpoint

A user holding only the read-only 'reader' role can send a {"language": "js"} command to POST /api/v1/command/{database} and execute arbitrary JVM code, reading files like /etc/passwd off the host — two cooperating defects (a missing permission check plus an unrestricted scripting language) rather than one. First of a five-advisory ArcadeDB batch published together this morning, all variations on the same theme: authorization checks that cover one code path but miss its siblings. Upgrade past 26.7.1 and audit for any custom endpoints reachable by non-admin roles.

ArcadeDB: the authorization gate above ships bypassable via SQL DEFINE FUNCTION

The permission check added for GHSA-48qw-824m-86pr only guards the polyglot engine's direct entry point — the SQL DEFINE FUNCTION ... LANGUAGE js route reaches the same JavaScript execution without ever touching it. Second advisory in this morning's ArcadeDB batch, and a clean illustration of why a single gate on a multi-path feature isn't a fix. Upgrade to 26.7.2, not 26.7.1 — 26.7.1 closes the direct route but leaves this one open.

ArcadeDB: IMPORT DATABASE lets any authenticated user SSRF the server and read local files

The SQL IMPORT DATABASE statement passes its source URL to the importer without validating scheme or destination and without requiring admin privileges — any authenticated user with SQL access can point it at cloud metadata endpoints or local files and read the response back through the import result. Third in this morning's ArcadeDB authorization batch. Restrict IMPORT DATABASE to admin roles at the network layer until 26.6.1 lands.

ArcadeDB: /ts/*, /batch/*, Prometheus and Grafana handlers skip the per-database authorization check entirely

About 14 HTTP handlers resolve the {database} path parameter and call getDatabase() without ever calling canAccessToDatabase() — they extend AbstractServerHttpHandler directly instead of the DatabaseAbstractHandler base class that holds the only per-database gate. Any authenticated user can read or write a database they have no grant on through these endpoints, a straightforward cross-database IDOR. Fourth advisory in the batch — patch first if you're triaging by blast radius, since this one skips authorization on the handler level rather than one code path.

ArcadeDB: read-only users can still mutate schema — last year's CVE-2026-44221 fix only patched one method

The fix for CVE-2026-44221 added an UPDATE_SCHEMA check to LocalDocumentType.createProperty but left the other public schema-mutating methods unchecked — a read-only API token can still alter database schema. Fifth advisory in today's ArcadeDB batch; the pattern across all five is identical: partial fixes that gate one method or one path and miss its neighbors. If you run ArcadeDB in production, this is a case for a full authorization-model audit rather than another point patch.

Pheditor's terminal feature: authenticated users bypass the command whitelist via shell substitution

Pheditor's terminal feature checks whether a submitted command starts with an allowed TERMINAL_COMMANDS value, then hands the full string to shell_exec() — command substitution via $() isn't blocked, so a user with only the 'terminal' permission can run arbitrary commands the whitelist was meant to prevent. Upgrade past 2.0.4; don't treat TERMINAL_COMMANDS as a security boundary on its own — see the companion advisory below for why.

Pheditor's fix for the bug above still leaves pipe, backtick, and newline injection open

After 2.0.6 added $ to the terminal-command blocklist, the pipe operator, backtick substitution, and raw newline bytes remained unfiltered — same authenticated-terminal RCE as GHSA-9643-6xjp-vx57, just through a different shell metacharacter. Two advisories, one root cause: denylisting shell metacharacters instead of allowlisting commands. If you're patching Pheditor this morning, verify the fix is an allowlist rewrite, not another character bolted onto the same blocklist.

MCP Python SDK: HTTP transports trust a session ID alone, no principal check

The SSE and Streamable HTTP server transports route requests to an existing session based only on the session identifier — anyone who learns or guesses a session ID can send JSON-RPC messages on someone else's session without re-authenticating as that principal. Affects mcp <= 1.27.1. If you're running an MCP server behind either HTTP transport, treat session IDs as bearer credentials until you patch — don't log them, and don't let them land in URLs that end up in access logs.

MCP Python SDK: experimental multi-client task handlers let any client cancel another's tasks

The default handlers installed by server.experimental.enable_tasks() don't check which session created a task before acting on it — on a server with more than one connected client, any client can observe, read results from, and cancel another client's tasks. Same affected range as the session-hijack advisory above (mcp >= 1.23.0, <= 1.27.1). If you've enabled the experimental tasks feature on a multi-tenant MCP server, disable it or patch before assuming task isolation holds.

Envoy Gateway: xDS control plane leaks config data in GatewayNamespaceMode via a missing unary interceptor

In GatewayNamespaceMode, the xDS gRPC server's JWT auth only covers streaming RPCs via a StreamInterceptor — the underlying go-control-plane server also exposes unary Fetch endpoints for every discovery service, and nothing authenticates those. Highest-severity of six new Envoy Gateway advisories published this morning against the 1.8.0 pre-release line (1.8.0-rc.0 through 1.8.1, and pre-1.7.4). Upgrade before exposing the xDS port beyond the cluster if you run GatewayNamespaceMode.

Envoy Gateway: unlocked Wasm cache read/write race in ServeHTTP

A probabilistic read/write race in the Wasm module cache, reachable by a pod-network attacker who floods GET requests while churning EnvoyExtensionPolicy objects with distinct Wasm URLs. One of six Envoy Gateway advisories in today's batch on the 1.8.0 pre-release line; no public repro yet per the advisory, so patch on the normal cycle rather than treating it as urgent.

Envoy Gateway: OCI layer extraction allocates buffer size straight from an untrusted tar header

Image-fetch code allocates make([]byte, h.Size) from the tar header's declared size before validating it against actual layer content — a malicious or compromised OCI registry in the fetch path can force large allocations and degrade the controller. Requires egress to an attacker-controlled registry with no allowlist, which is the default posture. Add a registry allowlist for EnvoyExtensionPolicy Wasm sources; the patch alone won't help if that trust model stays wide open.

Envoy Gateway: nil-pointer crash when a SecurityPolicy targets a TCPRoute without spec.authorization

A SecurityPolicy attached to a TCPRoute with spec.authorization omitted triggers a nil-dereference — straightforward denial of service against the controller, no auth bypass. Fourth of six Envoy Gateway advisories in this batch. If you template SecurityPolicy objects, add an explicit (even empty) spec.authorization block until the fix ships.

Envoy Gateway: Wasm HTTP fetch decompresses gzip with no output-size limit

EnvoyExtensionPolicy's Wasm fetch decompresses gzip content before checking size, and the optional sha256 field doesn't help since verification happens post-decompression — a classic gzip-bomb DoS against the controller. A tenant that can create EnvoyExtensionPolicy objects and host a gzip bomb at a reachable URL is all it takes. Cap decompression output size at the proxy layer until a fix lands.

Envoy Gateway: custom backendRefs skip the cross-namespace ReferenceGrant consent check

Extension-managed custom backendRefs from an HTTPRoute to another namespace's backend resource are accepted without a matching ReferenceGrant — the namespace owning the target resource never gets to opt in, breaking the Gateway API's cross-namespace consent model. Sixth of today's Envoy Gateway advisories, and the one access-control gap in a batch that's mostly crash/DoS bugs. Audit any custom backendRef extensions for cross-namespace references that shouldn't be allowed.

kuma-dp skips TLS certificate verification against an HTTPS control plane when no CA is configured

When an operator points kuma-dp at an HTTPS control plane without supplying a CA certificate, TLS peer verification is silently disabled rather than failing closed — the dataplane's authentication token then goes out over a connection an on-path attacker can intercept and use to impersonate the control plane. Companion advisory below covers the same gap in kumactl. Always set an explicit CA certificate for HTTPS control-plane connections; don't rely on the client failing safe when one is missing.

kumactl has the same silent TLS-verification bypass as kuma-dp when no CA is configured

Same root cause as GHSA-wvmp-6r4v-j6cv, this time in the operator-facing kumactl CLI: an HTTPS control-plane profile without a CA certificate connects with verification disabled, and user or admin API tokens go out over that unverified connection where an on-path attacker can grab them. Check both your dataplane bootstrap config and your kumactl profiles for an explicit CA — in both cases, 'CA not provided' silently means 'verification off' rather than failing closed.

Nuclio Dashboard: unauthenticated path traversal in spec.handler writes files anywhere in the container

POST /api/functions requires no authentication by default (NOP auth mode), and the spec.handler field is split only on ':' with no path validation on the module portion — an attacker can traverse outside the intended function directory and write files elsewhere in the Dashboard container. If Nuclio's Dashboard is reachable without your own auth layer in front, that's the real exposure here; NOP mode was never meant to face untrusted networks.

Diesel: use-after-free when deserializing a SQLite database from a byte buffer

SqliteConnection::deserialize_readonly_database passes a &[u8] buffer straight to libsqlite3, which requires the buffer to stay alive for the life of the connection — Diesel doesn't enforce that lifetime, so a buffer dropped while the connection is still open produces a use-after-free. Exploitability depends on how your code manages the buffer's lifetime relative to the connection; audit any path that loads a SQLite DB from an in-memory buffer via this function and upgrade to 2.3.10 once available.

nimiq-primitives: crafted state-sync proof crashes a syncing node via out-of-bounds panic

A malicious peer acting as a state-sync source can send a TrieChunk proof with an oversized child suffix that overflows the fixed 63-byte KeyNibbles backing array, panicking the process. A sync-time DoS, not a compromise, and paired with a near-identical panic below in the same trie-proof code. Relevant only if you run a nimiq node that accepts state-sync from untrusted peers.

nimiq-primitives: companion panic in TrieProof::verify via an unwrap on equal-length keys

Same state-sync DoS shape as GHSA-5rg2-xv9j-gv5p, different code path: child_index() unconditionally unwraps a lookup that fails when two proof nodes share an identical key, which a malicious peer can force with a crafted TrieChunk. Both nimiq-primitives panics are fixed in 1.6.0 — upgrade once rather than patching one and missing the other.