Development record
Baseline.validate sanitises final_url alone while echoing the entry key, url and quoted fields raw, so a committed citations-baseline entry writes ESC/bidi/zero-width to the terminal through the blocking docs-lint gate
issueresolvedminoriss-384
Baseline.validate sanitises final_url alone while echoing the entry key, url and quoted fields raw, so a committed citations-baseline entry writes ESC/bidi/zero-width to the terminal through the blocking docs-lint gate
Evidence
internal/core/lint/baseline.go:187sanitisese.FinalURL(the iss-359 rung) while the same loop emits the map key (who := "citation baseline entry " + k,baseline.go:175),e.URL(:178), andquote(e.LastChecked)/quote(e.Outcome)/quote(e.Verification)/quote(e.VerifiedOn)(:191-207) raw; the resulting*BaselineErrorreaches the terminal viacli.Run's error surface (internal/surface/cli/cli.go:2859-2868), which appliesscrubPaths(a path redactor), nevertermsafe.- The file's own threat model names a hostile branch (
baseline.go:71-74), and the honest producer (SaveBaselineviacite refresh) validates on the way out — so the raw-emitting branches are reachable only with hand-edited or hostile committed input. - Reproduced end-to-end: a poisoned committed baseline entry (key carrying U+202E + ESC + U+200B,
outcomecarrying ESC) made the blockingdocs lintgate exit 1 with raw ESC, bidi and zero-width bytes on stderr — including through the:187refusal message itself, whosewhoprefix carries the unsanitised key. - Refuter verdict: CONFIRMED (minor, security) — the incomplete-fix residue of iss-359's
Baseline.validaterung; distinct from iss-259/iss-264 (different surfaces, per iss-359's own precedent). The wider gap —cli.Runnever passing core errors throughtermsafe— is noted as the generalisation.
Frontmatter
| id | iss-384 |
|---|---|
| type | issue |
| lifecycle | resolved |
| severity | minor |
.abcd/work/issues/resolved/iss-384-baseline-validate-sanitises-final-url.md
open on GitHub ↗ · commit history ↗
mentions4
- dcn-26082000000000082026-08-20 — Bug-hunt round 3 (hunt B), branch bughunt-b/round-3. Baseline
- iss-259intent-store paths render to the terminal unsanitised in several intent verbs: intent plan prints res.Intent.Path and intent create prints the minted path without termsafe.Sanitize, and a hostile clone can commit a drafts/itd-N-<slug>.md whose filename tail carries control bytes (intentFileRe admits anything but a newline after the id), reaching the owner's terminal as escape sequences. The promote render sanitises its two paths as of spc-24; close the class once by sweeping the sibling intent renders through termsafe.Sanitize.
- iss-264cmd/record-lint prints Finding.File and Finding.Message raw — no termsafe.Sanitize and no path scrub on the findings path (its scrubPaths covers only the two error exits), so any rule echoing repo content lets a hostile clone inject terminal escapes into CI logs, and any finding message embedding an os error can leak absolute paths. The abcd CLI surface sanitizes at its findings renderer; the standalone binary does not. Found by the spc-27 security review, which also caught (and the change fixed) the one in-diff instance.
- iss-359cite fetch records a redirect-controlled FinalURL verbatim, so C1, bidi and zero-width runes in a hostile Location query reach abcd docs lint --json and the committed citations baseline raw; the termsafe doc claim that encoding/json escapes control characters is false for those classes