A real-time security guardrails system that automatically scans code generated by Claude Code for vulnerabilities, secrets, and insecure patterns — and blocks dangerous actions before they execute.
Built with Claude Code hooks, a Node.js scanning engine, and a React dashboard.
- What It Does
- Screenshots
- Quick Start
- Running with Docker
- Commands Reference
- Using Personally
- Using in Your Organisation
- How Hooks Work
- What Gets Detected
- Safety Levels
- API Endpoints
- Project Structure
- Logging
- License
When Claude Code tries to write a file containing secrets, SQL injection, eval(), or other vulnerabilities — the PreToolUse hook blocks the write and tells Claude to fix it:
When Claude Code tries to run rm -rf /, git push --force main, cat .env, DROP DATABASE, or other destructive commands — they get denied before execution:
🚨 [rm-root] Dangerous command blocked: rm targeting root filesystem
Command: rm -rf /
⛔ [git-force-main] Dangerous command blocked: Force push to main/master
Command: git push --force origin main
⛔ [cat-env] Dangerous command blocked: Reading .env file — may expose secrets
Command: cat .env
Run manual scans on any codebase to find secrets, OWASP vulnerabilities, insecure dependencies, and dangerous code patterns:
Monitor everything in a live dashboard — security score, severity breakdown, category distribution, hook activity log, and detailed findings:
Security score gauge (0-100), severity bar chart, category donut chart, and hook activity log showing blocked events with timestamps, tools, and reasons.
Terminal output showing scan results with color-coded severity, file locations, descriptions, and code snippets.
PreToolUse hook blocking dangerous Bash commands (rm -rf, force push, curl|bash, cat .env) and malicious code writes (AWS keys, hardcoded passwords).
- Node.js >= 18
- npm >= 9
- Claude Code CLI installed (install guide)
- Docker (optional)
# Clone the repo
git clone https://github.com/yourusername/claude-security-guardrails.git
cd claude-security-guardrails
# Install dependencies
npm installnpm run setup-hooksOutput:
+ PreToolUse hook installed (BLOCKS writes with critical/high issues)
+ PostToolUse hook installed (reports findings + saves to dashboard)
── How it works ──────────────────────────────────
PreToolUse → Runs BEFORE Write/Edit/Bash
🚫 BLOCKS dangerous commands (rm -rf, force push, etc.)
🚫 BLOCKS code with secrets/vulnerabilities
PostToolUse → Runs AFTER Write/Edit
📊 Scans file, saves results to dashboard
──────────────────────────────────────────────────
npm run scan -- ./test-fixtures/npm run devOpen http://localhost:5173 in your browser.
That's it. Hooks are active, the scanner is ready, and the dashboard is live.
No database required. Single container serves both the API and dashboard.
# Build and start
docker compose up -d
# View logs
docker compose logs -f
# Stop
docker compose down# Build
docker build -t claude-security-guardrails .
# Run
docker run -d -p 3001:3001 --name security-guardrails claude-security-guardrailsOpen http://localhost:3001 — both the API and the dashboard are served from the same port.
Docker Compose uses a named volume scan-data to persist scan results and activity logs across container restarts.
| Command | Description |
|---|---|
npm install |
Install all dependencies |
npm run setup-hooks |
Install Claude Code hooks (one-time) |
npm run scan -- <path> |
Scan a file or directory |
npm run scan -- <path> --json |
Scan with JSON output |
npm run scan -- <path> --dry-run |
Scan without saving results |
npm run scan:results |
Show latest scan results as JSON |
npm run server |
Start API server only (port 3001) |
npm run dashboard |
Start dashboard only (port 5173) |
npm run dev |
Start both API + dashboard |
docker compose up -d |
Run everything in Docker |
docker compose down |
Stop Docker |
You can use this on your own machine for all your Claude Code projects. Here's how:
The default setup. Hooks only activate when Claude Code is working inside this project directory.
cd claude-security-guardrails
npm run setup-hooks # hooks written to .claude/settings.json in this projectPros: No impact on other projects, easy to customize per-project. Cons: Only protects this one project.
Install hooks globally so they activate in every project you use Claude Code in.
Step 1: Copy hook scripts to a permanent location:
mkdir -p ~/.claude/hooks
cp hooks/pre-tool-use.js ~/.claude/hooks/
cp hooks/post-tool-use.js ~/.claude/hooks/
# Also copy the scanner (hooks depend on it)
cp -r scanner/ ~/.claude/hooks/scanner/Step 2: Edit ~/.claude/settings.json (global config):
{
"hooks": {
"PreToolUse": [
{
"matcher": "Write|Edit|Bash",
"hooks": [{
"type": "command",
"command": "node ~/.claude/hooks/pre-tool-use.js"
}]
}
],
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [{
"type": "command",
"command": "node ~/.claude/hooks/post-tool-use.js"
}]
}
]
}
}Step 3: Update the require() paths inside the copied hook scripts to point to the new scanner location (~/.claude/hooks/scanner/...).
Now every Claude Code session on your machine is protected — regardless of which project you're in.
Keep the dashboard running as a background service to monitor all Claude Code activity:
# Add to your shell profile (.zshrc / .bashrc)
alias security-dashboard="cd ~/claude-security-guardrails && npm run dev"Or use Docker:
docker run -d --restart unless-stopped -p 3001:3001 --name security-guardrails claude-security-guardrailsThe dashboard is always at http://localhost:3001.
When teams use Claude Code, AI-generated code can introduce:
- Hardcoded secrets (API keys, passwords, connection strings)
- OWASP vulnerabilities (SQL injection, XSS, command injection)
- Dangerous commands (
rm -rf, force push to main,DROP DATABASE) - Insecure dependencies and code patterns
You want guardrails that protect every developer automatically, without relying on individual discipline.
Add the .claude/ directory and hooks to your organisation's repos. When any developer clones the repo and uses Claude Code, hooks activate automatically.
What to add to each repo:
your-org-repo/
├── .claude/
│ └── settings.json ← hooks auto-activate
├── .claude-hooks/
│ ├── pre-tool-use.js ← blocking hook
│ ├── post-tool-use.js ← reporting hook
│ └── scanner/ ← scanning engine
│ ├── scanners/
│ │ ├── secrets.js
│ │ ├── owasp.js
│ │ ├── codePatterns.js
│ │ └── dangerousCommands.js
│ └── utils/
│ ├── severity.js
│ └── activityLog.js
└── src/
└── ...
.claude/settings.json:
{
"hooks": {
"PreToolUse": [{
"matcher": "Write|Edit|Bash",
"hooks": [{
"type": "command",
"command": "node .claude-hooks/pre-tool-use.js"
}]
}],
"PostToolUse": [{
"matcher": "Write|Edit",
"hooks": [{
"type": "command",
"command": "node .claude-hooks/post-tool-use.js"
}]
}]
}
}Pros: Zero setup for developers, version-controlled, customizable per-repo. Cons: Need to add to each repo (automate with a template or CI step).
For Claude Code on an enterprise plan, admins can enforce hooks via managed settings that developers cannot override.
Via environment variable (set in MDM profiles, login scripts, or CI):
export CLAUDE_SETTINGS_OVERRIDES='{
"hooks": {
"PreToolUse": [{
"matcher": "Write|Edit|Bash",
"hooks": [{
"type": "command",
"command": "node /opt/company/claude-hooks/pre-tool-use.js"
}]
}]
}
}'Via managed policy file (distributed via MDM/Chef/Puppet/Ansible):
Place at a system-level path that Claude Code reads on startup. This ensures hooks are enforced even if a developer modifies their local settings.
Pros: Enforced org-wide, developers can't disable it, centrally managed. Cons: Requires enterprise plan, MDM/deployment infrastructure.
Run the dashboard as a shared service that all developer hooks report to:
Step 1: Deploy the dashboard on an internal server:
# On your internal server / Kubernetes / ECS
docker compose up -dStep 2: Configure developer hooks to POST activity to the central server:
Update activityLog.js to send events to a central API in addition to (or instead of) local file storage. This gives you:
- Org-wide view of what Claude Code is doing across all developers
- Central log of all blocked commands and code writes
- Aggregated security metrics for compliance reporting
Step 3: Set up alerts (Slack, PagerDuty, email) for critical blocked events.
In addition to Claude Code hooks, add the scanner to your CI/CD pipeline:
# .github/workflows/security-scan.yml
name: Security Scan
on: [push, pull_request]
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- run: npm install
- run: npm run scan -- . --json > scan-results.json
- name: Check for critical issues
run: |
CRITICALS=$(node -e "const r=require('./scan-results.json'); console.log(r.severityCounts.critical)")
if [ "$CRITICALS" -gt 0 ]; then
echo "::error::Found $CRITICALS critical security issues"
exit 1
fiThis gives you a safety net even if someone bypasses local hooks.
| Layer | What | How |
|---|---|---|
| Developer machine | Block dangerous actions in real-time | Hooks via per-repo .claude/settings.json or enterprise managed settings |
| Central dashboard | Org-wide visibility + monitoring | Docker on internal server |
| CI/CD | Safety net for anything that slips through | GitHub Actions / GitLab CI running the scanner |
| Alerts | Immediate notification on critical events | Slack/PagerDuty integration on the dashboard |
Claude Code tries to write code or run a command
│
▼
┌─────────────────────────────────────┐
│ PreToolUse Hook │
│ ✓ Write/Edit → Scan for secrets, │
│ vulnerabilities, insecure code │
│ ✓ Bash → Check for dangerous │
│ commands (rm -rf, force push) │
└──────────────┬──────────────────────┘
┌──────┴──────┐
BLOCKED ALLOWED
(denied) (executed)
│
▼
┌────────────────────┐
│ PostToolUse Hook │
│ Full scan + save │
│ results to │
│ dashboard │
└────────────────────┘
Hook scripts communicate with Claude Code via stdin/stdout JSON:
Claude Code → pipes JSON to hook's stdin:
{ "tool_name": "Bash", "tool_input": { "command": "rm -rf /" } }
Hook → writes JSON to stdout:
Allow: {}
Block: { "hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "deny",
"permissionDecisionReason": "🚨 rm targeting root filesystem"
}}
| Settings location | Scope |
|---|---|
.claude/settings.json (in project) |
This project only |
~/.claude/settings.json (home dir) |
All projects for this user |
CLAUDE_SETTINGS_OVERRIDES env var |
Enforced, cannot be overridden |
| Pattern | Severity |
|---|---|
AWS Access Keys (AKIA...) |
Critical |
| AWS Secret Keys | Critical |
GitHub Tokens (ghp_, gho_, etc.) |
Critical |
Private Keys (-----BEGIN RSA PRIVATE KEY-----) |
Critical |
Database Connection Strings (mongodb://, postgres://) |
Critical |
Slack Tokens (xoxb-...) |
Critical |
| API Keys | High |
JWT Tokens (eyJ...) |
High |
| Hardcoded Passwords | High |
| Generic Secrets/Tokens | Medium |
| Pattern | Severity |
|---|---|
| SQL Injection (string concat in queries) | Critical |
Command Injection (exec() with user input) |
Critical |
XSS (innerHTML, dangerouslySetInnerHTML, document.write) |
High |
| SSRF (fetch/axios with user-controlled URLs) | High |
| Path Traversal (file ops with user input) | High/Medium |
CORS Misconfiguration (origin: '*') |
Medium |
| Category | Examples | Severity |
|---|---|---|
| Filesystem destruction | rm -rf /, rm -rf ~/, rm -rf . |
Critical |
| Disk wipe | dd of=/dev/sda, mkfs |
Critical |
| Fork bombs | :(){ :|:& };: |
Critical |
| Git disasters | git push --force main, git reset --hard, git clean -f |
High |
| Remote code execution | curl | bash, wget | sh |
High |
| Secrets exposure | cat .env, printenv, echo $SECRET_KEY |
High |
| Database destruction | DROP DATABASE, TRUNCATE TABLE |
High |
| System commands | shutdown, reboot, killall, chmod 777 |
High |
| Data exfiltration | curl -d @.env, scp .env, rsync secrets |
High |
Checks package.json for outdated packages with known CVEs (lodash, jsonwebtoken, shell-quote, axios, minimist, etc.) and flags wildcard/broad version ranges.
| Pattern | Severity |
|---|---|
eval() usage |
Critical |
new Function() constructor |
High |
| MD5 hashing for passwords | High |
Disabled TLS (rejectUnauthorized: false) |
High |
Math.random() for security purposes |
Medium |
Sensitive data in console.log() |
Medium |
| Hardcoded IPs and ports | Low |
The PreToolUse hook has a configurable safety level in hooks/pre-tool-use.js:
const SAFETY_LEVEL = 'high'; // 'critical' | 'high' | 'strict'| Level | What gets blocked |
|---|---|
critical |
Only catastrophic: leaked secrets, eval(), rm -rf /, fork bombs |
high (default) |
+ risky: XSS, SQL injection, force push main, git reset --hard, weak crypto |
strict |
+ cautionary: all medium/low findings, any force push, sudo rm, docker prune |
| Endpoint | Method | Description |
|---|---|---|
/api/results |
GET | All scan results (array) |
/api/results/latest |
GET | Most recent scan result |
/api/summary |
GET | Aggregated summary (score, counts) |
/api/activity |
GET | Recent hook events (blocked/allowed/findings) |
/api/activity/stats |
GET | Blocked/allowed/warning counts |
/api/health |
GET | Health check |
claude-security-guardrails/
├── package.json # Root workspace config
├── Dockerfile # Multi-stage Docker build
├── docker-compose.yml # Docker Compose config
├── README.md # This file
├── assets/ # Screenshots
│ ├── dashboard-overview.png
│ ├── dashboard-full.png
│ ├── dashboard-score-charts.png
│ ├── cli-scan-output.png
│ └── hook-blocking.png
├── scanner/ # Scanning engine
│ ├── index.js # Orchestrator
│ ├── cli.js # CLI interface
│ ├── server.js # Express API server
│ ├── scanners/
│ │ ├── secrets.js # 10 secret patterns
│ │ ├── owasp.js # 13 OWASP patterns
│ │ ├── dependencies.js # 16 vulnerable packages
│ │ ├── codePatterns.js # 11 code patterns
│ │ └── dangerousCommands.js # 30+ dangerous commands
│ ├── utils/
│ │ ├── fileUtils.js
│ │ ├── severity.js
│ │ ├── store.js
│ │ └── activityLog.js
│ └── data/ # Auto-created
│ ├── scan-results.json
│ └── activity-log.json
├── hooks/ # Claude Code hooks
│ ├── pre-tool-use.js # BLOCKING hook
│ ├── post-tool-use.js # Reporting hook
│ └── setup-hooks.js # Installer
├── dashboard/ # React + Vite
│ └── src/
│ └── components/
│ ├── SecurityScore.jsx
│ ├── SeverityChart.jsx
│ ├── CategoryBreakdown.jsx
│ ├── ActivityLog.jsx
│ ├── RecentScans.jsx
│ ├── FindingsTable.jsx
│ └── Header.jsx
├── test-fixtures/ # Sample vulnerable files
└── .claude/
└── settings.json # Hook configuration
All hook activity is logged in two places:
1. File logs (per developer):
~/.claude/hooks-logs/2026-02-19.jsonl
2. Dashboard logs (visible in UI):
scanner/data/activity-log.json
Example log entry:
{
"id": "evt_1771501445272_wvx6",
"timestamp": "2026-02-19T11:44:05.272Z",
"action": "blocked",
"hook": "PreToolUse",
"tool": "Bash",
"target": "rm -rf /",
"reason": "rm targeting root filesystem",
"severity": "critical",
"patternId": "rm-root"
}


