Skip to content

Six source-scanning gates strip comments with a naive regex that a /* inside a string literal blinds — the repo already has the string-aware masker they should use #9367

Description

@os-zhuang

Filed unassigned from the #8985 dev seat (session session_012WKSnqAaoqtW3QX7SSf1Vk, PR #9365). Found while reverse-verifying a pin I wrote; the same mechanism bit my own detector first, which is how it was noticed at all.

The mechanism

Several check-*.mjs gates decide "is this code or prose?" with

source.replace(/\/\*[\s\S]*?\*\//g,'')

That regex has no idea what a string literal is. Any source carrying /*inside a string — a glob ('src/**/*', `@objectstack/*`), a route wildcard (`/api/v1/auth/*`, `/_console/*`) — opens a phantom block comment that runs to the next real */, usually a docblock hundreds of lines further down, taking every line of real code in between with it.

The failure direction is the dangerous one: silent under-reporting. The gate reports clean over code it never looked at. AGENTS.md already names this class — "a verifier that silently degrades (reusing a stale build, skipping a check it could not run) is worse than no verifier, because it reports success."

Measured

How much real source each file loses to the naive strip, on 0a5adbaed:

filelinesremoved by the naive strip
packages/cli/src/commands/start.ts469265 (56%)
packages/cli/src/commands/serve.ts41721058
packages/cli/src/utils/console.ts653209

Those totals include genuine comments, so here is the isolated proof on start.ts, which is where I hit it: --auth-secret's flag description contains the literal /api/v1/auth/*, and the phantom comment it opens closes against a docblock 250 lines later. A detector looking for a specific assignment reported the file clean while the assignment was demonstrably present on line 327 — the phantom span covered lines 133 to 384.

105 non-test source files under packages/*/src and packages/*/*/src carry a string literal containing /*, i.e. carry the trigger:

grep -rlE "['\"\`][^'\"\`]*/\*[^'\"\`]*['\"\`]" --include=*.ts packages/*/src packages/*/*/src | grep -v '\.test\.\|\.spec\.' | wc -l

Gates using the vulnerable spelling

  • scripts/check-dispatcher-error-vocabulary.mjs:152 (stripComments, used at 6 call sites)
  • scripts/check-error-code-casing.mjs:130
  • scripts/check-error-status-conformance.mjs:248
  • scripts/check-examples-live-imports.mjs:173
  • scripts/check-test-source-alias.mjs:683
  • scripts/check-platform-checklist.mjs:183

The fix already exists in-tree

scripts/pm/dispatch-gates.mjs exports maskComments — built on a character-class scanner that tracks strings, templates and regex literals, and blanks comment spans instead of deleting them, so line numbers survive. Its docblock was written for the neighbouring failure (comments contributing false hints). The gates above should call it rather than each keeping a private naive copy.

check-error-code-casing.mjs is halfway there already — it blanks rather than deletes, preserving line numbers — but it is still regex-based and equally blind to strings.

What is measured and what is not

Measured: the mechanism, the phantom span on a real repo file, the swallowed-line counts, the 105 triggering files, and that a correct helper exists.

Not measured: whether any of the six gates currently has a live false negative — that needs each gate's scan surface intersected with the triggering files, and then a pattern that actually falls inside a swallowed span. So this is a latent hazard with a proven mechanism, not a demonstrated live miss. Whoever picks it up should measure that intersection first; it also decides whether this is a same-day fix or a ratchet risk.

Worth noting the repair is cheap and uniform (swap the private stripComments for the shared maskComments), and that doing it may raise findings in gates that are currently under-reporting — a widening, not a regression.


Generated by Claude Code

Metadata

Metadata

Assignees

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions