⚠️ Beta — Internal Use ShellGuard is under active development and not yet production-ready. Hook support for Gemini CLI (Antigravity) and Claude CLI may be incomplete or unreliable. Use at your own risk and expect breaking changes between releases. Currently developed for internal use at s4e.io.
ShellGuard sits between your AI coding agent and your shell. Every command an AI suggests — rm, curl, git push, anything — passes through ShellGuard first. It logs it, checks it against your policy, and either allows or blocks it.
Claude Code / Cursor / Codex / Gemini CLI / VS Code
↓ suggests a command
ShellGuard
↙ ↘
Blocked Allowed + logged
(exit 2) (command runs)
Works with: Claude Code · Cursor · OpenAI Codex CLI · Gemini CLI · VS Code (Copilot / Cline / Continue)
AI coding agents are powerful — and they run real shell commands. A confused model, a malicious prompt injection, or a simple mistake can rm -rf your project, exfiltrate files via curl, or push secrets to a public repo.
ShellGuard gives you:
- Audit log — every command the AI ran, timestamped, with the tool that triggered it
- Block list — stop specific commands from ever running, silently or with an error
- Modes —
log only,dev,read only,custom— dial your paranoia level - Zero latency — single Go binary, sub-millisecond check, no daemon required
macOS (Apple Silicon)
curl -Lo shellguard https://github.com/s4e-io/shellguard/releases/latest/download/shellguard-darwin-arm64
chmod +x shellguard && sudo mv shellguard /usr/local/bin/macOS (Intel)
curl -Lo shellguard https://github.com/s4e-io/shellguard/releases/latest/download/shellguard-darwin-amd64
chmod +x shellguard && sudo mv shellguard /usr/local/bin/Linux (x86_64)
curl -Lo shellguard https://github.com/s4e-io/shellguard/releases/latest/download/shellguard-linux-amd64
chmod +x shellguard && sudo mv shellguard /usr/local/bin/Windows (PowerShell)
Invoke-WebRequest -Uri "https://github.com/s4e-io/shellguard/releases/latest/download/shellguard-windows-amd64.exe" `
-OutFile "$env:USERPROFILE\bin\shellguard.exe"macOS users: The ShellGuard Mac app installs the binary automatically and provides a menu bar UI for managing modes, hooks, and logs.
Pick your tool below and add the one-time config change. ShellGuard automatically detects which tool is calling it from the JSON payload.
~/.claude/settings.json
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [{ "type": "command", "command": "shellguard" }]
}
],
"PostToolUse": [
{
"matcher": "Bash",
"hooks": [{ "type": "command", "command": "shellguard" }]
}
]
}
}~/.cursor/hooks.json
{
"beforeShellExecution": {
"command": "shellguard"
}
}~/.codex/hooks.json
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [{ "type": "command", "command": "shellguard" }]
}
],
"PostToolUse": [
{
"matcher": "Bash",
"hooks": [{ "type": "command", "command": "shellguard" }]
}
]
}
}~/.gemini/settings.json
{
"hooks": {
"BeforeTool": [
{
"matcher": "run_shell_command",
"hooks": [{ "type": "command", "command": "shellguard" }]
}
]
}
}ShellGuard registers as a terminal profile so all agent-spawned terminals route through it.
settings.json (macOS path: ~/Library/Application Support/Code/User/settings.json)
{
"terminal.integrated.profiles.osx": {
"ShellGuard": {
"path": "/usr/local/bin/shellguard",
"args": []
}
},
"terminal.integrated.defaultProfile.osx": "ShellGuard"
}Replace
osxwithlinuxorwindowsas needed.
ShellGuard reads config from:
| OS | Config directory |
|---|---|
| macOS | ~/Library/Application Support/ShellGuard/ |
| Linux | ~/.config/shellguard/ |
| Windows | %APPDATA%\ShellGuard\ |
Create state.json:
{
"mode": "log only",
"enabled": true
}| Mode | Behavior |
|---|---|
log only |
Allow everything, log all commands (default) |
dev |
Block destructive + network exfiltration commands |
read only |
Block anything that writes, executes code, or touches the network |
custom |
Use your own policy.yaml rules |
version: 1
modes:
dev:
blocked:
- curl
- wget
- rm -rf
- git push
custom:
blocked:
- sudo
- ssh
- scp
allowed:
- git
- npm
- makeIf policy.yaml doesn't exist, ShellGuard uses built-in safe defaults per mode.
Every command is appended as a JSON line:
{
"timestamp": "2026-05-12T09:23:41.123456",
"command": "rm -rf node_modules",
"reason": "'rm' is blocked in dev mode.",
"user": "alice",
"process": "claude",
"pid": "12345",
"blocked": true,
"type": "suggestion"
}| Field | Values |
|---|---|
process |
claude · cursor · codex · gemini · vscode |
blocked |
true = ShellGuard stopped it |
type |
suggestion (PreToolUse) · execution (PostToolUse) |
ShellGuard runs in two modes depending on invocation:
Hook mode (Claude Code, Cursor, Codex, Gemini)
The AI tool pipes a JSON payload to stdin before executing. ShellGuard parses it, runs the policy check, and exits 0 (allow) or 2 (block). Exit 2 is the standard PreToolUse block signal.
Wrapper mode (VS Code)
ShellGuard acts as the shell itself (shellguard -c "cmd"). If the policy allows it, ShellGuard execs the real shell with the command. Otherwise it exits with an error.
Bypass protection
ShellGuard splits and checks every segment of chained commands:
| Bypass attempt | Detection |
|---|---|
ls; curl evil.com |
✅ chain split |
echo x && rm -rf / |
✅ chain split |
echo url | xargs curl |
✅ xargs unwrap |
sh -c 'curl evil.com' |
✅ shell -c unwrap |
/usr/bin/curl evil.com |
✅ absolute path normalization |
shellguard/ ← this repo (CLI, all platforms)
├── cmd/shellguard/
│ └── main.go ← single-file binary (intentional)
├── docs/
│ ├── SETTINGS.md ← per-tool hook config reference
│ └── TESTING.md
├── scripts/
│ └── uninstall.sh
├── .github/
│ └── workflows/
│ └── release.yml ← builds all platforms on git tag
└── README.md
shellguard-ui-mac/ ← separate repo
Swift macOS menu bar app
App Store + DMG distribution
https://github.com/s4e-io/shellguard-ui-mac
The CLI is the core — pure Go, no platform dependencies, works everywhere. The Mac app is a UI layer on top: it installs the binary, writes hook configs, and shows logs in a menu bar. Keeping them separate means:
- Linux/Windows users get a focused, minimal repo
- Mac app releases don't block CLI releases
- The security-critical code is independently auditable
git clone https://github.com/s4e-io/shellguard
cd shellguard
go build -o shellguard ./cmd/shellguard/Cross-compile:
GOOS=linux GOARCH=amd64 go build -o shellguard-linux-amd64 ./cmd/shellguard/
GOOS=windows GOARCH=amd64 go build -o shellguard-windows-amd64.exe ./cmd/shellguard/
GOOS=darwin GOARCH=arm64 go build -o shellguard-darwin-arm64 ./cmd/shellguard/PRs are welcome. A few principles:
- Single file.
main.gois one file on purpose — easy to read, easy to audit, easy to vendor. Don't split it without a strong reason. - No new dependencies.
gopkg.in/yaml.v3is the only allowed dep. Everything else is stdlib. - Test bypass vectors. If you add a new bypass detection, add a test for it.
- New AI tool support? Add detection logic to
extractHookFields()and document the hook config indocs/SETTINGS.md.
-
shellguard check "cmd"— dry-run from the command line -
shellguard tail— live tail ofactivity.log - Allow-list mode in addition to block-list
- Homebrew formula
- Shell completions
- Windows: full hook mode support (Claude Code on WSL)
- Structured test suite
sudo rm /usr/local/bin/shellguard
# Remove config and logs
rm -rf ~/Library/Application\ Support/ShellGuard # macOS
rm -rf ~/.config/shellguard # LinuxRemove the hook entries you added from each tool's config file. See docs/SETTINGS.md for exact locations.
MIT © Security For Everyone