Repository navigation
fix(qa): sanitize evidence_field diagnostics against terminal escape injection - #379
Conversation
Post-merge QA (glm)Lens: requirements + adversarial. Sanitizes the evidence_field diagnostic against terminal escape injection (#378). sanitizeDiagnosticField keeps only [A-Za-z0-9_.-] and collapses every other rune to '?', applied at the only unescaped sink in runQA (doctor.go evidence_field line). Checked the other diagnostic channels: evidence_reason is a fixed token set from code, evidence_detail values are %q-quoted or numeric, and the Error() string is not printed raw in this path, so no bypass remains. Test asserts ESC[31m renders as evil??31m??0m and no raw bytes reach stderr. Multibyte runes collapsing to a single '?' only shortens output; fail-closed semantics and exit codes unchanged. No findings. Verdict: clean |
Post-merge QA (deepseek)Lens: evidence + test design. The merge does what #378 asked for the evidence_field line: sanitizeDiagnosticField keeps [A-Za-z0-9_.-] and collapses the rest, the regression case reproduces the escape payload and pins the sanitized rendering, and the focused suites plus go vet are stated as run. It does not close the class the issue names in its second acceptance criterion ('The same rule applies to any future diagnostic fields derived from caller-supplied input'): the same code path still prints evidence_detail with %s, and for expected_array rejections that Detail is built from caller-supplied JSON object keys joined with %s, so terminal escape bytes still reach stderr through the sibling diagnostic line. The PR body states that evidence_detail is unaffected 'because it already quotes values with %q', which is not true for the object-keys construction in validateEvidence, and the new test asserts only the field line, so nothing in the suite would catch the surviving path. Test design gap: the new case checks that the sanitized field line is present but never asserts that no raw ESC byte appears anywhere in the stderr stream, which is the property the issue actually asks for. Blocking (1)
Question (1)
Verdict: blocking |
Fixes #378
Problem
The
evidence_field=diagnostic shipped in #376 prints the failing field name unescaped. Forunknown_fieldandduplicate_fieldrejections the field value comes from a caller-supplied JSON key name in the--evidencepayload, so a key containing terminal escape or control characters could print raw bytes to the operator's stderr.Change
runQAnow renders the diagnostic field throughsanitizeDiagnosticField, which keeps only printable ASCII word characters ([A-Za-z0-9_.-]) and collapses every other rune to?. Escape and control sequences can no longer reach the terminal.evidence_detailis unaffected because it already quotes values with%q.Test
Added a
TestQARunEvidenceDiagnosticAttributioncase with an evidence record whose unknown field key containsESC[31msequences. RED before the fix (raw escape bytes in stderr), GREEN after (evidence_field=evil??31m??0m). Focused./internal/cliand./internal/qapisuites plusgo vetpass.Refs #376, #305.