v vanemmerik.ai / SUPPLY-CHAIN
Supply Chain · Watch Saturday · 08 August 2026 End-of-day synthesis 4 watches · 30 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 — Six coordinated GitPython option-injection RCEs and a four-bug CodeIgniter batch dropped the same day Coinspect confirmed a six-year-old crypto-js weak-RNG bug has been silently seeding real wallets.

Today's disclosures cluster around developer tooling rather than production web stacks — the two biggest stories are both dependencies that touch CI/CD, git operations, and local dev environments, not runtime request handling.

GitPython shipped six coordinated advisories in a single day: a forged git-config directive that overwrites core.sshCommand for RCE, an unsafe-option-guard bypass via short-option token smuggling, arbitrary repository creation through an unvalidated .gitmodules name, a Repo.init() template kwarg that plants a malicious hook, a read-tree --index-output injection that overwrites arbitrary files, and a pathspec-file information-disclosure sibling — all closed by the same upgrade past 3.1.57. CodeIgniter matched it with four advisories of its own (an upload-validation bypass that chains to RCE, a deleteBatch() SQL injection, an UploadedFile::move() path-traversal writeout, and a spoofable isSecure() header check), all fixed in 4.7.4. go-git's symlink-follow and ref-path-traversal pair, both rooted in trusting repository-controlled strings as filesystem paths, rhymes with the GitPython batch — same lesson, different library.

The most consequential single item isn't new: Coinspect's Ill Bloom investigation confirmed that crypto-js's non-cryptographic WordArray.random(), fixed upstream in 2020, has been used by downstream wallet applications to generate BIP39 seed phrases with a brute-forceable search space — old lockfile pins are still draining wallets six years later. Head Mare's TrueConf installer-trojanizing campaign remains the day's one confirmed active-exploitation story.

→ Operational priority for the night grep CI images and dev-tooling lockfiles for gitpython and pin past 3.1.57 — one upgrade closes six RCE-class bugs at once.

12:00 ET · Forenoon Watch

crypto-js's WordArray.random() isn't a CSPRNG — downstream wallets used it to generate BIP39 seed phrases

CryptoJS.lib.WordArray.random() in crypto-js < 4.0.0 isn't cryptographically secure: nominal requests for 128 or 256 bits of entropy collapse to an effective search space of roughly 2^39 and 2^47 possibilities, small enough to brute-force on commodity hardware. Coinspect's Ill Bloom investigation confirmed downstream wallet applications used this function as the entropy source for BIP39 recovery phrases — a guessable seed phrase is a drained wallet. crypto-js 4.0.0 shipped in 2020, but old lockfile pins keep this alive; grep transitive dependencies for crypto-js < 4.0.0 anywhere near key or seed generation.

CodeIgniter's is_image / mime_in upload validators can be bypassed into remote code execution

CodeIgniter's is_image and mime_in upload-validation rules (< 4.7.4) can be tricked into accepting a file with a dangerous extension; combined with trusting the client-supplied filename and saving into a web-accessible directory — both common defaults — that's remote code execution. It's a three-condition chain, but all three show up in CodeIgniter apps that skip an independent ext_in check. Patch to 4.7.4, or in the meantime move uploads outside the public web root and force server-generated filenames.

CodeIgniter's Query Builder deleteBatch() drops the escape flag on where()-bound values — SQL injection

CodeIgniter's Query Builder deleteBatch() (4.3.0–4.7.3), when used with where() conditions, substitutes the bound WHERE values into the generated SQL with their escape flag ignored — user-controlled input passed to where() before deleteBatch() is interpreted as SQL, not data. Regular delete() escapes correctly; this is scoped to the batch-delete path only. Patch to 4.7.4 and grep for deleteBatch() calls chained off a where() built from request input — same release as the upload-validation and path-traversal bugs above, so take all three together.

CodeIgniter's UploadedFile::move() writes outside the upload directory when called without a destination filename

Calling UploadedFile::move() without a second argument (< 4.7.4) uses the client-supplied filename unsanitized, so a name like ../../public/shell.php can write outside the intended upload directory. The patch only sanitizes the no-argument path — if your code explicitly passes a client-provided name as the destination, you're still exposed after upgrading. Same 4.7.4 release as the other two CodeIgniter advisories today.

jsii-diff's npm: package argument allows shell command injection

jsii-diff's npm:<package-spec> argument, used to pull a comparison package straight from the registry for API-diffing, is passed through in a way that lets a specially crafted specifier execute arbitrary shell commands. jsii-diff runs in AWS CDK / jsii construct-library CI pipelines comparing API surface across versions, so this is a build-time RCE risk anywhere that argument can come from an untrusted branch or PR. Patch to 1.131.0 and audit CI jobs that feed external input into a jsii-diff npm: argument.

pymdown-extensions' caret/tilde/betterem/magiclink processors have exponential-backtracking regexes reachable by default

Four inline processors in pymdown-extensions — caret, tilde, betterem, magiclink — carry exponential-backtracking regexes reachable through the library's default configuration; a crafted Markdown line under 50 bytes drives markdown.markdown() into unbounded CPU, with runtime growing exponentially per added byte. Any service rendering untrusted Markdown (comments, wikis, issue bodies) is a one-line DoS away from a stuck worker. No patched version yet at ≤ 11.0.0 — wrap the render call in a timeout until a fix lands.

go-git worktree operations follow symlinks into the repository's own .git directory

go-git's worktreeFilesystem wrapper blocks path strings containing .git or traversal sequences, but doesn't stop filesystem calls from following a symlink already present in the worktree — clone a malicious repo containing a symlink into .git, and a subsequent worktree operation can write into the repo's own metadata directory. Pairs with the reference-name traversal bug below; both hit go-git v5 ≤ 5.19.1 and v6 ≤ 6.0.0-alpha.4. If go-git clones untrusted repos in your CI or tooling, patch both together.

GitPython's unsafe-option guard can be bypassed via short-option token smuggling — command execution

GitPython's check_unsafe_options guard — meant to block injected flags like --upload-pack= on clone/fetch/pull/push/blame/archive — can be bypassed by pairing a single-character kwarg with split_single_char_options=False; the guard's candidate list doesn't account for the resulting joined argv token, so git parses it as an unsafe option anyway and executes it. It's an incomplete fix of an earlier guard (GHSA-r9mr-m37c-5fr3), and one of several GitPython option-injection advisories disclosed together today. Upgrade past 3.1.57 and don't assume allow_unsafe_options=False alone is a safe boundary if any of these kwargs come from user input.

GitPython lets a forged git-config option name overwrite core.sshCommand — RCE on the next git operation

GitPython's config-name validator neutralizes CR/LF/NUL but not =, #, or whitespace in an option name, so a crafted name like sshCommand = touch <cmd> # is written verbatim and git parses it as core.sshCommand = touch <cmd> — a forged config directive that executes on the next git operation. The most dangerous of today's GitPython batch since it forges config directly rather than smuggling a single flag. Upgrade past 3.1.57.

GitPython creates an arbitrary git repository outside the working tree via an unvalidated .gitmodules submodule name

GitPython derives the on-disk path for a submodule's .git/modules/<name> directory straight from the attacker-controlled .gitmodules section name with no validation — a malicious repo can set a traversal name like ../../../../home/victim/.something and get GitPython to initialize a full git repository at an arbitrary filesystem path. No special API call needed; a plain clone with submodule handling is the trigger. Upgrade past 3.1.57.

GitPython's Repo.init() forwards unguarded git init options — a template kwarg plants a hook for RCE

Repo.init() forwards kwargs verbatim to git init with no unsafe-option guard, so an attacker-controlled template kwarg pointing at --template=<dir> copies that directory's hooks into the new repo's .git/hooks — arbitrary code execution on the next git operation. --template was already guarded on the clone path; init never got the same treatment until this disclosure. Upgrade past 3.1.57.

GitPython's read-tree option forwarding lets an injected --index-output overwrite an arbitrary file

IndexFile.from_tree, IndexFile.reset, and IndexFile.merge_tree append caller-influenced treeish strings positionally to git read-tree with no guard and no -- separator; an injected --index-output=<path> flag wins on last-occurrence and overrides the method's internal temp path, clobbering an arbitrary file with a valid git-index blob. Last of today's six-advisory GitPython option-injection batch — upgrade past 3.1.57 covers all of them.

Head Mare exploits unpatched TrueConf servers to swap client installers for backdoored ones

The Head Mare group has been exploiting vulnerabilities in unpatched TrueConf video-conferencing servers to replace legitimate client installers with trojanized versions carrying backdoors — a server-side compromise weaponized into a software-distribution attack, the same installer-as-dropper shape as other campaigns flagged here. Patch the server first; a clean client build doesn't help if the install source itself stayed compromised during the exposure window. If TrueConf is in your environment, verify installer hashes against TrueConf's official values before trusting anything downloaded recently.

Hono's memo() can serve one user's server-rendered HTML to another

Hono's memo() from hono/jsx caches a server-rendered result keyed only on props, but request-scoped reads via JSX Context, useRequestContext(), or getContext() take no part in that comparison — a memoized component can return HTML rendered for a different user's request. Any app wrapping a component that reads per-request context (auth state, tenant ID, locale) in memo() risks cross-user leakage. Patched in hono 4.12.34; audit memo()-wrapped components for hidden context reads.

Hono's languageDetector middleware has an O(n²) tag-normalization path — algorithmic-complexity DoS

Hono's languageDetector middleware normalizes language tags by repeatedly slicing and rejoining subtags, an O(n²) pattern scaling with the number of hyphen-separated subtags in a value pulled from a query param, cookie, or Accept-Language header — all exposed under the default detector config. Patched in 4.12.34, the same release as the memo() fix above.

Netty's RedisArrayAggregator retains stale partial-aggregate state after a maxElements failure

RedisArrayAggregator clears retained partial-aggregate state when maxNestedArrayDepth is exceeded but not when the sibling maxElements limit is — a peer can start a valid RESP array, send a bulk-string child, then a nested array header past maxElements, and if the channel stays open after the resulting decoder exception, later messages get consumed into the stale pre-error aggregate. Patch netty-codec-redis to 4.1.136.Final / 4.2.16.Final if you proxy or terminate RESP traffic through Netty.

API Platform Core doesn't type-check relation IRIs — a relation can be denormalised as the wrong resource type

API Platform's serializer doesn't validate the resource type returned when resolving relation IRIs — getResourceFromIri() skips passing an operation context, so the is_a type check is bypassed and a caller with write access to a relation can point it at a resource of an unintended type. Patch to 4.1.30 / 4.2.26 / 4.3.12 depending on branch; review any writable relation where the related resource's type matters for authorization.

Nuxt's dev server leaks the project root path and a workspace UUID via a header-trusting DevTools endpoint

When a Nuxt dev server is bound to a network-reachable interface (nuxt dev --host), the default-enabled Chrome DevTools workspace endpoint returns the absolute project root path and a persistent workspace UUID; the gate meant to restrict it to local requests trusts client-supplied Sec-Fetch-Site metadata rather than the actual peer address. Dev-only exposure, but anyone sharing the network during nuxt dev --host testing can fingerprint your project layout. Patched in nuxt 4.5.1 / 3.21.10.

go-git resolves a malicious reference name as a literal path, letting a crafted ref write outside reference storage

A malicious Git server can advertise a reference name like refs/heads/../../config that go-git (≤ 5.19.1 / v6 ≤ 6.0.0-alpha.4) resolves as a literal path under .git/, letting a crafted ref overwrite files like .git/config or .git/HEAD outside the intended reference storage. Same root cause — trusting repository-controlled strings as paths — as the worktree-symlink bug above; patch both together if go-git touches untrusted remotes.

GitPython's IndexFile.remove() / Head.checkout() leak arbitrary file contents through a git error message

IndexFile.remove() and Head.checkout() forward kwargs unguarded to git rm / git checkout; combining --pathspec-from-file with --pathspec-file-nul makes git echo the full contents of a caller-chosen file back through its unmatched-pathspec error, which GitPython surfaces verbatim in GitCommandError.stderr — the information-disclosure sibling to the RCE and traversal bugs in today's GitPython batch. Upgrade past 3.1.57.

DOMPurify's IN_PLACE mode can leave a detached, hook-removed subtree executable — XSS

During IN_PLACE sanitization, a hook that removes an element can leave that element's detached descendants executable: _sanitizeElements() returns immediately when a hook detaches the current node, without neutralizing its children, so a detached image can retain an attacker-set onload handler and fire even though it's disconnected from the returned, clean root. Only affects callers using IN_PLACE with a hook that removes elements — check any custom uponSanitizeElement/beforeSanitizeElements hook for that pattern.

Smarty's stream: resource type bypasses Security::$streams = null, enabling local file read

Smarty 5.8.0's Security::$streams = null setting, meant to disable all PHP stream wrappers in templates, doesn't apply to Smarty's own stream: resource type — a template using {include file="stream:php://filter/..."} reaches StreamPlugin directly and bypasses the check, enabling local file read even with streams nominally disabled. Pairs with the symlink traversal bug below; if you run untrusted or third-party Smarty templates with Security enabled, patch both.

Smarty's trusted-directory check doesn't resolve symlinks, so a planted symlink escapes the sandbox

Smarty's directory trust check (Security::_checkDir()) normalizes paths as strings via _realpath() but doesn't resolve symlinks, so a symlink placed inside a trusted secure_dir passes the check while file_get_contents() follows it to an arbitrary file outside the sandbox, e.g. /etc/passwd. Requires an attacker who can place a symlink in a trusted directory — relevant for multi-tenant template setups. Patched at 5.8.2 (5.x) and 4.5.7 (4.x).

06:00 ET · Morning Watch

Craft CMS passkey login accepts replayed WebAuthn assertions — a captured login body mints a fresh session

Craft CMS's passkey login endpoint takes requestOptions straight from the unauthenticated request body and never persists the updated WebAuthn credential counter after a successful assertion, so a captured login request — pulled from a proxy log, APM tool, or compromised same-origin script — can be replayed to open another authenticated session for that user. This defeats the one-time challenge and signature-counter guarantee passkeys exist to provide, turning a single exposed request body into a reusable bearer credential. Patch to 5.10.5, and check whether anything in your stack logs or proxies request bodies on the login path — that's the exposure this bug depends on.

CodeIgniter's isSecure() trusts spoofable X-Forwarded-Proto and Front-End-Https headers

CodeIgniter's IncomingRequest::isSecure() trusts the X-Forwarded-Proto and Front-End-Https headers on any incoming request, so an attacker who can reach the app directly — or whose proxy forwards client-supplied headers unmodified — can spoof an HTTP request into looking secure. Anything gated on isSecure(), force_https(), or forceGlobalSecureRequests, including cookie Secure flags and forced-HTTPS redirects, can be silently bypassed. Upgrade to 4.7.4, and confirm your reverse proxy overwrites rather than forwards those headers before they reach the app.

Ruby's JSON gem has a use-after-free crash in ResumableParser#partial_value on truncated duplicate-key streams

Ruby's JSON native extension (2.20.0–2.21.1) frees its input buffer but leaves stale pointers in parser state; reconstructing a truncated object with duplicate keys via ResumableParser#partial_value dereferences them, an AddressSanitizer-confirmed heap-use-after-free that crashes the process. It's DoS-only — no code execution or data exposure is claimed — but any network service streaming untrusted JSON through ResumableParser and calling partial_value can be remotely killed. No patched version is listed in the advisory yet; track it if you use the resumable parser on attacker-reachable input.

Hono's Proxy Helper forwards headers an origin marked connection-scoped instead of stripping them

Hono's Proxy Helper (hono/proxy) strips the standard hop-by-hop headers but not the additional header names an origin lists in its own Connection header, a narrow RFC 9110 compliance gap rather than a live exploitation path. Impact is limited to leaking internal metadata an origin intended for its immediate peer, and only when that origin declares non-standard headers as connection-scoped. Fixed in 4.12.34; low priority unless you proxy responses from an origin that does this.