/security-review and Claude Code Review are AI reviewers: they comment, and Code Review's check run always completes as neutral, so neither blocks a merge. For checks that can block, add hooks in .claude/settings.json that run on every edit, and a required status check on the pull request.
What Anthropic ships, and what it doesn't do
| Tool | What it does | Blocks a merge? |
|---|---|---|
| Permission modes | Decide whether Claude may run a command, edit a file or call a tool | No; they govern actions, not code |
/security-review | Asks Claude to review your pending changes for security issues | No; it's a review in your session |
anthropics/claude-code-security-review | GitHub Action that runs an AI security review on a PR with your Claude API key and comments on it | Only if you build that into your workflow |
| Claude Code Review | Managed PR reviewer; posts findings by severity in a check run | No: the check run always completes as neutral. Anthropic's docs suggest reading the severity counts from the check output in your own CI if you want to gate |
These are good tools. They are also model-based, so their findings can vary between runs. The rest of this page adds the deterministic part: rule IDs, the same result on the same code, and a check that can fail.
Inside Claude Code: hooks on every edit, install and stop
pip install skylos
skylos agent install-hooks --skylos-bin skylos # writes .claude/settings.json
Run /hooks in Claude Code to see what was added. From then on:
- After each
Edit/Write/MultiEdit, a PostToolUse hook checks only the lines Claude just changed. When Claude wroteos.system('echo hi ' + name)into a Click command, Claude got back:Skylos found 1 issue(s) in the lines you just changed. Fix them before moving on: - pkg/tool.py:8 SKY-D212/SKY-D203 Possible command injection (os.system): tainted input. - Before a
Readof a file containing a hard-coded secret, a PreToolUse hook denies it, so the key isn't sent to the model provider. - Before a Bash install of a package that doesn't exist (
pip install reqeusts,uv add numpyy), a PreToolUse hook denies it. - When Claude tries to stop with an issue it introduced still open, the Stop hook sends it back with the list. With
[tool.skylos.done]committed, the Stop hook also re-runs your tests and blocks on deleted or skipped tests (real output).
The full settings.json, the JSON each hook returns and the latency numbers are on Claude Code hooks examples for security.
Committing the hooks for a team
.claude/settings.json is usually committed. By default the installer writes the absolute path of the Skylos that ran it; on a teammate's machine without that path the hooks do nothing (they never block). --skylos-bin skylos writes a plain skylos instead, so each machine uses the one on its own PATH. Personal overrides go in .claude/settings.local.json.
Claude can edit .claude/settings.json like any file. skylos done --base origin/main reports a change to it as SKY-A114 ("Skylos settings and hooks left alone"), and blocks by default.
Before you accept "done"
Run two commands on Claude's branch. They answer different questions:
skylos done --base origin/main # did it delete, skip or weaken tests?
skylos . --diff-base origin/main --danger --quality # did it remove an auth, CSRF or rate-limit check?
skylos done re-runs your tests and compares them with the base (what it checks). It does not look at security controls: a branch whose only change was deleting @login_required got Verdict: PASS. The --diff-base scan reported that same deletion as SKY-L021 Security control regression: Auth decorator @login_required was removed (details).
If the repository is noisy, record today's findings with skylos baseline . and scan with --baseline, so only new findings show.
On the pull request: a check Claude can't edit
skylos cicd init --no-upload
This writes a GitHub Actions workflow with a changed-line scan ("Skylos Quality Gate") and, when it finds a pytest project, a "Skylos Done" job. No Skylos account or API key is needed. Two things to add in 4.47.1:
- The removed-controls job. The generated scan uses
--diff, which keeps only findings on changed lines, so it did not report a deleted@login_requiredin our test and the gate passed. Add the removed-controls job. - Branch protection. Make the Skylos jobs required status checks. Claude Code Review's neutral check can sit next to them as advice.
What to look for in Claude Code diffs
| Risk | Why broad refactors produce it | Covered by |
|---|---|---|
| Removed auth or permission checks | Refactors optimize structure, not security intent | --diff-base scan (SKY-L021), named patterns only |
Insecure convenience flags (verify=False, debug=True) | "Working now" beats "safe in production" | Edit hook and --danger scan |
| Helpers nobody calls after extraction | The agent leaves plausible but unused code | skylos . dead-code scan |
| Calls to APIs or helpers that don't exist | The code looks valid even when the call is wrong | SKY-D224, SKY-L012 (details) |
| Deleted or skipped tests | A green run is the goal | skylos done |
| Tenant filters, business rules, CORS | Application-specific | Your tests and human review |
What this setup doesn't do
- It is not a sandbox. The hooks don't restrict commands, files or network access. Use Claude Code's permission settings for that.
- It doesn't see application-specific authorization, such as a tenant filter dropped from a query.
- It doesn't replace a reviewer. It removes the machine-checkable problems before one reads the diff.
Where to go next
- Claude Code hooks examples for security
- Claude Code Stop hook: block "done" until tests pass
- Cursor security scanner for Python
- GitHub Copilot code review and security
- How to secure an MCP server before you trust it with your code
References
Running this across a team? These checks are free in the CLI. Skylos Cloud keeps the results in one place: the Free plan adds a pass/fail check on pull requests and scan history for one project, and the Workspace plan adds up to 10 projects, approvals for findings you decide not to fix, pull request comments, and audit exports.