This is the record of an abcd-managed repository

abcdBetav0.16.2 · 2026-11-06

Development record

2026-08-01 — itd-105 / spc-21, MERGE-GATE fix (sixth round, test-hardening only): a fresh merge-gate security reviewer reproduced a TWO-HOP bypass of the same fetch-origin allowlist test, and this entry also corrects the claim two entries above. That entry said the allowlist "taints any name whose own assignment line references itself", which is exactly what it did — and exactly why it closed only the ONE-hop case, not "the self-referential bypass class" the fix commit's message implied. Two names that reference each OTHER (`repo_url="${GH_MIRROR:-$gh_default}"` then `GH_MIRROR="$repo_url"`) leave neither line self-referential, so the per-line check passed the planted script green while `GH_MIRROR=https://attacker.invalid/x` genuinely redirected the fetch — the reviewer verified that against the real script logic with a curl-argv-recording shim. `TestBootstrapFetchOriginsAreConstants`'s allowlist is now computed by `bootstrapSafeNames`, which propagates taint to a FIXPOINT over the assignment graph instead of scanning each line once: a name is script-local only if every assignment of it draws on constants, on `CLAUDE_PLUGIN_ROOT`, or on names already safe AT THAT POINT in the file, and the pass repeats until no name is newly tainted. What that closes is chains of self- and mutual reference of ANY length — one hop, the reviewer's two, and the three-hop laundering variant are all detector cases now, alongside the reproduction spliced into the committed script's own bytes. What it does NOT claim is completeness: it is a fixpoint over `$NAME`/`${NAME}` references in `name=` assignments, not a shell parser, so a value laundered through a construct that scan does not model (an `eval`, an eval-time expansion, a name assembled at runtime) is outside what it proves. The reference scan deliberately stays order-INSENSITIVE on the usage side, because a shell function body runs long after the line defining it and "used before assigned" is not a defect there. Second finding in the same pass: the curl scan filtered lines on the substring `curl -`, so any invocation whose first argument is not a flag (`curl "$url" -o /dev/null`) was skipped ENTIRELY — it could be missing `-q` or the transport pin and never be looked at, while the call count stayed consistent with itself because the scan was its own counter. curl is matched as a command WORD now (line head, after a shell operator, command substitution, path prefix, or keyword), with mentions — `command -v curl`, the refusal message's prose, `.curlrc` — held out as non-invocations by their own detector cases. Detector-first on both, each pre-fix behaviour restored in place and watched to fail: the two-hop, three-hop and planted-script cases reported nothing under the old taint rule, and five curl shapes (flags after the URL, no flags at all, an absolute path, after `if`, downstream of a pipe) were invisible to the old substring filter. `hooks/bootstrap.sh` is UNCHANGED — the reviewer's finding is that the regression guard was weaker than its own comment claimed, not that the shipped bytes have a live seam. Left alone deliberately, out of scope for this pass and unfixed: `SSLKEYLOGFILE`/`QLOGDIR` are not scrubbed, the lock and temp `mkdir`s take the ambient umask, and every tool the script runs is PATH-resolved (an actor who can write the PATH can replace `curl` outright, which no shell script closes).

decisiondcn-2608010000000013

2026-08-01 — itd-105 / spc-21, MERGE-GATE fix (sixth round, test-hardening only): a fresh merge-gate security reviewer reproduced a TWO-HOP bypass of the same fetch-origin allowlist test, and this entry also corrects the claim two entries above. That entry said the allowlist "taints any name whose own assignment line references itself", which is exactly what it did — and exactly why it closed only the ONE-hop case, not "the self-referential bypass class" the fix commit's message implied. Two names that reference each OTHER (repo_url="${GH_MIRROR:-$gh_default}" then GH_MIRROR="$repo_url") leave neither line self-referential, so the per-line check passed the planted script green while GH_MIRROR=https://attacker.invalid/x genuinely redirected the fetch — the reviewer verified that against the real script logic with a curl-argv-recording shim. TestBootstrapFetchOriginsAreConstants's allowlist is now computed by bootstrapSafeNames, which propagates taint to a FIXPOINT over the assignment graph instead of scanning each line once: a name is script-local only if every assignment of it draws on constants, on CLAUDE_PLUGIN_ROOT, or on names already safe AT THAT POINT in the file, and the pass repeats until no name is newly tainted. What that closes is chains of self- and mutual reference of ANY length — one hop, the reviewer's two, and the three-hop laundering variant are all detector cases now, alongside the reproduction spliced into the committed script's own bytes. What it does NOT claim is completeness: it is a fixpoint over $NAME/${NAME} references in name= assignments, not a shell parser, so a value laundered through a construct that scan does not model (an eval, an eval-time expansion, a name assembled at runtime) is outside what it proves. The reference scan deliberately stays order-INSENSITIVE on the usage side, because a shell function body runs long after the line defining it and "used before assigned" is not a defect there. Second finding in the same pass: the curl scan filtered lines on the substring curl -, so any invocation whose first argument is not a flag (curl "$url" -o /dev/null) was skipped ENTIRELY — it could be missing -q or the transport pin and never be looked at, while the call count stayed consistent with itself because the scan was its own counter. curl is matched as a command WORD now (line head, after a shell operator, command substitution, path prefix, or keyword), with mentions — command -v curl, the refusal message's prose, .curlrc — held out as non-invocations by their own detector cases. Detector-first on both, each pre-fix behaviour restored in place and watched to fail: the two-hop, three-hop and planted-script cases reported nothing under the old taint rule, and five curl shapes (flags after the URL, no flags at all, an absolute path, after if, downstream of a pipe) were invisible to the old substring filter. hooks/bootstrap.sh is UNCHANGED — the reviewer's finding is that the regression guard was weaker than its own comment claimed, not that the shipped bytes have a live seam. Left alone deliberately, out of scope for this pass and unfixed: SSLKEYLOGFILE/QLOGDIR are not scrubbed, the lock and temp mkdirs take the ambient umask, and every tool the script runs is PATH-resolved (an actor who can write the PATH can replace curl outright, which no shell script closes).

Frontmatter

iddcn-2608010000000013
typedecision
date2026-08-01

mentions2