Skip to content

Fix: raw control bytes in three scripts — one silently disabled an audit check - #97

Merged
emmanuelgjr merged 4 commits into
mainfrom
fix/control-bytes-in-scripts
Sep 15, 2026
Merged

emmanuelgjr merged 4 commits into
mainfrom
fix/control-bytes-in-scripts

Conversation

@emmanuelgjr

Copy link
Copy Markdown
Contributor

Plan ID: — (found while verifying T-STRAT01 research) Ticket: — Wave: —
Constraints honored: C1/C2/C4 untouched (scripts only, no data, no docs/).

Stacked on #37: the new test file triggers the CI jobs that are red on main (Drift 11). No generated files, so no conflicts with the rest of the stack.

What was wrong

Three scripts on main contain raw control bytes where an escape sequence was intended. Git classifies each file as binary, so no diff of them has ever been readable in a PR.

File Bytes Intended Effect
scripts/audit-incidents.mjs 0x08 BACKSPACE the regex word-boundary escape (backslash + b) The "advisory-style description" check could never match anything. It has reported 0 regardless of input since #21.
scripts/export-olir.mjs 0x00 NUL a NUL escape (backslash + u0000) used as a key separator Works at runtime; file unreviewable
scripts/density-report.js 0x00 NUL same Works at runtime; file unreviewable

Likely origin: the agent tooling unescapes backslash sequences before writing, so a typed escape lands as the raw byte.

Hence a guard rather than a one-off repair.

Changes

  • The bytes are replaced with the escape text (backslash + b, backslash + u0000), built from character codes so tooling couldn't re-mangle them.
  • New scripts/text-integrity.test.mjs: fails on any control byte (other than tab, LF, CR) in a tracked text file. It checks numeric byte values and contains no escape sequences itself.

Verify

  • Behaviour unchanged where it should be:
    • reports/olir-nist-csf-2-0.csv and reports/density-violations.md are byte-identical before and after (sha256 compared).
    • The audit regex now matches "This flaw allows unauthenticated attackers to read files", and still doesn't match "Attackers used prompt injection to exfiltrate". The backspace version matched neither.
    • No current incident description matches it, so today's audit report is unchanged. The fix matters for future records.
  • The guard, negative-tested: against the previous scripts it reports exactly scripts/audit-incidents.mjs:75 byte 8; scripts/density-report.js:47 byte 0; scripts/export-olir.mjs:82 byte 0.
$ node scripts/validate.js        0 error(s), 84 warning(s), 312 passed (unchanged)
$ npm test                        52/52 on repeated runs

One intermittent failure seen, and it is not from this PR. In about 1 of 5 local runs, exports.test.mjs fails with Unterminated string in JSON. That's the pre-existing race where generate.test.mjs rewrites data/entries while another suite reads them. #87 fixes it (skip-identical-writes), but this branch is built on #37, which doesn't have that fix yet. I captured the failing run to confirm the cause, rather than assuming it.

🤖 Generated with Claude Code

https://claude.ai/code/session_014SfR2YzLxRH54DAVzDk8gR

emmanuelgjr and others added 3 commits August 30, 2026 10:10
Every docs/*.js bundle carried a `// Generated: <today>` header. Nothing
else in the generator output varies between runs, so that one line was
the whole reason a regenerate on a different day showed four dirty
files — and, since #30, the reason the Generator reproducibility job and
the `committed entries match a fresh generation` test could only pass on
the day the bundles were last committed.

- generate.js: drop the run-date lines; the Source header now reads the
  version from package.json instead of a hard-coded, stale `v1.5.2`.
- generate.test.mjs: assert no bundle header names a run or carries a date.
- validate.yml: the reproducibility job now diffs every generated
  artefact (backlinks.json, backlinks.js, frameworks-registry.js too).
- CONTRIBUTING.md: document the build contract — generated files, the
  determinism requirement, and why the bundles are committed (Pages
  serves docs/ from main; no deploy workflow exists).

Determinism only. No structural, route, layout or logo change (C2).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0147wBugcuzLkswKPqgofcke
Conflicts were only in the four generated webapp bundles, and only in
their header lines: #92 regenerated them with a `// Generated:` date
that this branch removes. Resolved by re-running scripts/generate.js on
the merged sources; a second run is byte-identical.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014SfR2YzLxRH54DAVzDk8gR
Three scripts on main held raw control bytes where an escape sequence
was meant. Git classifies each as binary, so none of their diffs was
ever shown in review.

- scripts/audit-incidents.mjs: the "advisory-style description" regex
  meant a word boundary (backslash-b) at both ends but held two BACKSPACE
  bytes (0x08). The pattern could never match, so the check has reported
  0 regardless of input since #21. Now matches "allows unauthenticated
  attackers to ..." and not ordinary prose. (The current corpus has no
  matching description, so today's report is unchanged.)
- scripts/export-olir.mjs, scripts/density-report.js: composite-key
  separators were literal NUL bytes (0x00). Replaced with the escape text
  u0000, which yields the same runtime string: the OLIR CSV and density
  report are byte-identical before and after.

New scripts/text-integrity.test.mjs fails on any control byte in a
tracked text file. Against the previous tree it reports exactly these
three files; it checks byte values, so it contains no escapes a tool
could turn back into the bytes it looks for.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014SfR2YzLxRH54DAVzDk8gR
Base automatically changed from fix/T-ENG03-deterministic-webapp-build to main September 14, 2026 21:09
#37 landed as a squash, so this branch's copies of its commits resolve as identical content. Generated files re-run on the merged sources; a second generation is byte-identical.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014SfR2YzLxRH54DAVzDk8gR
@emmanuelgjr
emmanuelgjr merged commit f506290 into main Sep 15, 2026
11 of 12 checks passed
@emmanuelgjr
emmanuelgjr deleted the fix/control-bytes-in-scripts branch September 15, 2026 01:25
emmanuelgjr added a commit that referenced this pull request Sep 15, 2026
Generated files re-run on the merged sources; a second generation is byte-identical. text-integrity test passes on this branch's files.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014SfR2YzLxRH54DAVzDk8gR
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant