What happened
gate-48 csrf-cochange is red on nldesign (development vs origin/beta, hydra-gates @main). Nothing about CSRF changed in that diff. The gate matched a removed line of prose inside a class docblock:
- * (#[PublicPage] + #[NoCSRFRequired]) and the response contract are owned by
That line is part of a docblock rewrite describing where the auth posture is owned. No attribute and no annotation was removed; the surrounding diff replaces one explanatory paragraph with another.
Why
The detector matches the token anywhere on any removed line:
_csrf_removed=$(git diff -U0 "${BASE_REF}...HEAD" -- 'lib/Controller/*.php' 2>/dev/null \
| grep -E '^-.*(@NoCSRFRequired|#\[NoCSRFRequired\])' || true)
^-.* puts no constraint on code position, so a comment that names the attribute is indistinguishable from an attribute that was deleted.
This is the same defect class as #184 (gate-64 grepped a quoted string literal, so it matched comments and missed constants). A checker that greps a token rather than a code position fails in both directions.
Why this one is especially bad to leave
The fleet is currently being driven to green. The cheapest way to make this finding disappear is to reword a comment — which changes nothing about CSRF and teaches exactly the habit the gate exists to prevent. A gate that can be satisfied by editing prose is worse than no gate, because it manufactures the appearance of a security review.
Suggested fix
Require the token in a code position rather than anywhere on the line:
- attribute form: after
- and optional whitespace the content starts with #[, and the attribute list contains NoCSRFRequired;
- legacy docblock form: after
-, optional whitespace and an optional leading *, the content starts with @NoCSRFRequired.
The nldesign line fails both (its #[NoCSRFRequired] sits mid-sentence after (), while a genuine deletion of either form still matches.
Mutation check to include
The fixture needs both arms, or the fix is unfalsifiable:
- must stay green — a diff that only removes a comment line mentioning
#[NoCSRFRequired] in prose (the nldesign line verbatim).
- must go red — a diff that removes a real
#[NoCSRFRequired] attribute line with no frontend CSRF signal, and separately one that removes a real * @NoCSRFRequired docblock tag.
Arm 2 is the one that proves the fix did not simply disable the gate.
Measured on
hydra-gates @main (3438839), --app-dir nldesign --base origin/beta, scope 3118 files. nldesign is the only repo of the eight I surveyed where gate-48 fires at all, and its single finding is this false positive.
What happened
gate-48 csrf-cochangeis red on nldesign (developmentvsorigin/beta, hydra-gates @main). Nothing about CSRF changed in that diff. The gate matched a removed line of prose inside a class docblock:That line is part of a docblock rewrite describing where the auth posture is owned. No attribute and no annotation was removed; the surrounding diff replaces one explanatory paragraph with another.
Why
The detector matches the token anywhere on any removed line:
^-.*puts no constraint on code position, so a comment that names the attribute is indistinguishable from an attribute that was deleted.This is the same defect class as #184 (gate-64 grepped a quoted string literal, so it matched comments and missed constants). A checker that greps a token rather than a code position fails in both directions.
Why this one is especially bad to leave
The fleet is currently being driven to green. The cheapest way to make this finding disappear is to reword a comment — which changes nothing about CSRF and teaches exactly the habit the gate exists to prevent. A gate that can be satisfied by editing prose is worse than no gate, because it manufactures the appearance of a security review.
Suggested fix
Require the token in a code position rather than anywhere on the line:
-and optional whitespace the content starts with#[, and the attribute list containsNoCSRFRequired;-, optional whitespace and an optional leading*, the content starts with@NoCSRFRequired.The nldesign line fails both (its
#[NoCSRFRequired]sits mid-sentence after(), while a genuine deletion of either form still matches.Mutation check to include
The fixture needs both arms, or the fix is unfalsifiable:
#[NoCSRFRequired]in prose (the nldesign line verbatim).#[NoCSRFRequired]attribute line with no frontend CSRF signal, and separately one that removes a real* @NoCSRFRequireddocblock tag.Arm 2 is the one that proves the fix did not simply disable the gate.
Measured on
hydra-gates @main (
3438839),--app-dir nldesign --base origin/beta, scope 3118 files. nldesign is the only repo of the eight I surveyed where gate-48 fires at all, and its single finding is this false positive.