[security-guidance] Reviews that fail with API errors (e.g. HTTP 401) are reported as clean and marked reviewed
Summary
When the security review can't reach the model (e.g. HTTP 401), security-guidance logs "no vulnerabilities found", stays silent, and records the commit as reviewed. A review that never ran is indistinguishable from a clean one, and the commit isn't reviewed again by the push sweep.
Environment
- security-guidance 2.0.8 (claude-plugins-official)
- Claude Code 2.1.286 (desktop app), macOS 26.5.1
- First-party auth. The failing credential was an OAuth token that had been rotated or revoked since the session started.
What happens
Debug log from a commit review run with a revoked token:
Commit review: 1/1 sha(s) resolved, 1 files
agentic_review: investigate failed (Claude Code returned an error result: Failed to authenticate. API Error: 401 OAuth access token has been revoked. (exit code: 1)); falling back
API error: 401 - {"type":"error","error":{"type":"authentication_error","message":"OAuth access token has been revoked."},"request_id":null}
single: claude-opus-4-7 failed, falling back to sonnet
API error: 401 - {"type":"error","error":{"type":"authentication_error","message":"OAuth access token has been revoked."},"request_id":null}
LLM code review: no vulnerabilities found
Commit review: no security issues found
The hook exits 0 with no rewake. The only trace of the failure is in the metrics, which the user and agent never see:
{"api_calls": 1, "http_err_last": 401, "http_err_count": 2, "vulns_found": 0, "agentic": false, "agentic_fallback": 2, "api_error": 401, "commit_review": true}
The commit is also appended to .git/sg-reviewed-shas with vulns_found=0: _append_reviewed_shas runs after analyze_code_security "regardless of whether findings were emitted". So a later push sweep treats it as already reviewed and skips it.
The agentic attempt also took about 186 s to fail before falling back.
Why it matters
The feature's value is "no news is good news". With this behaviour, an expired or revoked credential, an outage, or a rate limit silently turns every review into a pass.
Suggested fix
- When every review call failed (
api_error/http_err_count > 0and no successful response), report it: a rewake orsystemMessagesuch as "Security review could not run (HTTP 401); this commit was not reviewed", instead of "no security issues found". - Don't append failed reviews to
sg-reviewed-shas, so the push sweep or a later run can still review the commit.
3 Comments
Thanks @evantayloryates for the report. I reproduced the same failure in the public source of this repository at
71cdddec623889d38af14b7a489670a03186f659and prepared the patch and regression tests below.The raw HTTP reviewer turns both a failed model call and a successful clean review into
(None, []). Commit review and push sweep then append the affected SHA(s) tosg-reviewed-shas. This also loses a failed review when the async agentic race's fallback raises.The patch uses
findings=Nonefor a failed review andfindings=[]for a completed clean review. Commit/push handlers stop before recording SHAs on failure. Stop restores its consumed touched-path state before reporting failure. Each failure emits an exit-2 diagnostic and a failure-specificrewakeSummaryinstead of claiming no vulnerabilities; it does not log credential or API response contents. Successful model fallback and a dual-or review with at least one successful leg still count as reviewed.Validation: Python 3.9.6 on macOS, actual
_call_claude/urllibrequests to a loopback HTTP fixture, actual temporary Git commits and a local bare push target, and the real commit/push/Stop handlers in isolated subprocesses. All credentials and model responses are synthetic. On the unmodified source, 5 of 12 tests fail; all 12 pass after the fix. A clean copy accepts the complete patch withgit apply --check, then also passes all 12 tests. Coverage includes failed commit/push not entering the ledger, recovery and re-review of the same commit, clean and finding-bearing success, primary-failure/sonnet-fallback success, dual-or partial success, and Stop failure preserving the touched paths and baseline.Scope: this repository's manifest is 2.0.0, while the report uses marketplace 2.0.8. I have not run a live Claude session, the marketplace package or a real Agent SDK reviewer; the actual terminal/mobile rendering of the async failure notification still needs product acceptance. The tests verify the emitted hook protocol, not that UI. No external model was called and no SDK was installed.
Run from the repository root:
External PR creation remains restricted to collaborators. Could a maintainer take this patch or identify the preferred contribution route? Credit for the original diagnosis belongs to @evantayloryates. I have not opened a PR or pushed a contribution branch.
<details>
<summary>Complete patch and regression tests</summary>
</details>
Hi, I'm picking this up. Plan:
analyze_code_securityreturnsfindings=Nonewhen every model call failed (vs[]for a completed clean review); the commit and push handlers stop before recording SHAs insg-reviewed-shason failure and report "security review could not run (HTTP <code>)" instead of "no security issues found"; the Stop hook keeps restoring its touched-path state and surfaces the failure once per session. — Sahil JagtapFix is up: https://github.com/sahiljagtap08/claude-code/pull/3 (branch
sahiljagtap/security-guidance-failed-review-not-clean, one commit on currentmain). Fork PRs are rejected on this repo right now, so a maintainer can cherry-pick:What it does:
analyze_code_securityreturnsfindings=Nonewhen every model call failed ([]still means a completed clean review). Commit review and push sweep check for that before_append_reviewed_shasand report "<scope> security review could not run (HTTP 401)" via rewakeSummary + exit 2, withreview_failed/api_errorin metrics. Stop keeps restoring its touched-path state and surfaces the failure once per session. Verified end-to-end against a loopback API in a temp git repo: 401 → exit 2, no ledger entry; clean 200 → unchanged. — Sahil Jagtap