Skip to content

feat: add gatekeeper plugin for auto-approve safe commands#30

Merged
amondnet merged 12 commits into
mainfrom
feat/gatekeeper-plugin
Feb 10, 2026
Merged

feat: add gatekeeper plugin for auto-approve safe commands#30
amondnet merged 12 commits into
mainfrom
feat/gatekeeper-plugin

Conversation

@amondnet

@amondnet amondnet commented Feb 9, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds the gatekeeper plugin, a two-layer security system for Claude Code that automatically approves safe commands and blocks dangerous operations while delegating unknown commands to an AI security agent for review.

Architecture

Layer 1: Pattern Matching (PreToolUse Hook)

  • Instant allow: Safe read-only commands (ls, cat, git status, etc.)
  • Instant deny: Dangerous operations (rm -rf, git push --force, etc.)
  • Unknown commands: Pass to Layer 2

Layer 2: AI Security Review (PermissionRequest Hook)

  • AI agent analyzes command intent and risk level
  • Provides security recommendations
  • Learns from user patterns for better future decisions

Key Features

  • ✅ Zero-friction for safe operations
  • ✅ Protection against accidental destructive commands
  • ✅ Intelligent unknown command review
  • ✅ Extensible pattern configuration
  • ✅ Full test coverage

Changes

  • Added plugins/gatekeeper/ directory with complete plugin implementation
  • Added gatekeeper entry to marketplace.json
  • Updated workspace configuration to include plugins/*

Plugin Structure

plugins/gatekeeper/
├── .claude-plugin/
│   └── plugin.json         # Plugin manifest
├── hooks/
│   └── hooks.json          # PreToolUse hook configuration
├── src/
│   ├── pre-tool-use.ts     # Pattern matching logic
│   └── pre-tool-use.test.ts # Test suite
├── README.md               # Plugin documentation
└── package.json            # Dependencies

Test Plan

  • Unit tests for pattern matching (allow/deny/unknown)
  • Test coverage for all command patterns
  • Integration test with PreToolUse hook
  • Verify hook registration in plugin.json

Related Documentation

  • See plugins/gatekeeper/README.md for usage guide
  • See docs/plugins.md for Claude Code plugin architecture
  • See docs/lessons-learned/ for plugin development best practices

Two-layer security plugin for Claude Code:
- Layer 1 (PreToolUse): pattern matching for instant allow/deny
- Layer 2 (PermissionRequest): AI agent review for unknown commands
@vercel

vercel Bot commented Feb 9, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
claude-code-plugins Ready Ready Preview, Comment Feb 10, 2026 2:03am

Request Review

The pre-tool-use.js build output is needed at runtime by the
PreToolUse hook, so it must be committed.
- Anchor all DENY rules with ^ to prevent matching in echo/comments
- rm -rf / now only matches exact root (not /var, /tmp, /home/...)
- rm -rf ~ now only matches current user home (not ~ubuntu, ~admin)
- Add regression tests for subdirectory paths and embedded patterns
@amondnet

amondnet commented Feb 9, 2026

Copy link
Copy Markdown
Contributor Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces the gatekeeper plugin, a valuable security addition for auto-approving safe shell commands. The core logic is sound, but I've identified a critical security vulnerability related to command chaining that needs to be addressed. I've also suggested several other security and usability improvements to the pattern matching rules. My review focuses on making the pattern-matching layer more robust before passing commands to the AI agent.

Comment thread plugins/gatekeeper/src/pre-tool-use.ts Outdated
Comment thread plugins/gatekeeper/src/pre-tool-use.ts
Comment thread plugins/gatekeeper/src/pre-tool-use.ts
Comment thread plugins/gatekeeper/src/pre-tool-use.ts
Comment thread plugins/gatekeeper/src/pre-tool-use.ts
- Fix crash on valid JSON non-object input (e.g. null, 42, [])
- Report invalid JSON to stderr with exit code 1 instead of silent exit 0
- Add .catch() handler to main() for unhandled promise rejections
- Document empty stdin passthrough intent with comment

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

4 issues found across 16 files

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="plugins/gatekeeper/src/pre-tool-use.ts">

<violation number="1" location="plugins/gatekeeper/src/pre-tool-use.ts:51">
P0: Security bypass: Command chaining allows dangerous commands to be auto-approved. A command like `ls; rm -rf /` starts with `ls` (matches ALLOW_RULES) but contains destructive operations that won't be caught by DENY_RULES. Consider checking for command separators (`;`, `&&`, `||`, `|`, `$()`, backticks) before auto-allowing, or only allowing commands that don't contain any separators.</violation>
</file>

<file name="plugins/gatekeeper/.gitignore">

<violation number="1" location="plugins/gatekeeper/.gitignore:1">
P2: `!dist/` re-includes the directory but still leaves its contents ignored due to the root `dist` ignore. If you intend to commit built artifacts under `plugins/gatekeeper/dist`, you also need to unignore the files themselves.</violation>
</file>

<file name="plugins/gatekeeper/hooks/hooks.json">

<violation number="1" location="plugins/gatekeeper/hooks/hooks.json:22">
P2: Security policy mismatch: The AI agent prompt approves force pushes to non-main branches, but the README documents git push as "non-force only". This inconsistency could lead to unexpected force pushes being approved. Consider aligning the AI agent policy with the documented behavior, or update the README to reflect that force push to non-main branches is allowed.</violation>
</file>

<file name="plugins/gatekeeper/src/pre-tool-use.test.ts">

<violation number="1" location="plugins/gatekeeper/src/pre-tool-use.test.ts:382">
P1: Missing security test: This test documents that chained commands are allowed if the first command is safe, but the test suite doesn't verify behavior for `npm test && rm -rf /` where a safe command is chained with a dangerous one. Based on the implementation's `^`-anchored patterns, this would be auto-allowed (a security gap). Consider adding a test that explicitly documents this limitation, e.g.:
```typescript
test('SECURITY NOTE: dangerous commands chained after safe commands are auto-allowed', () => {
  // This documents a known limitation - only the first command is checked
  expectAllow(bash('npm test && rm -rf /'))
})
```</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread plugins/gatekeeper/src/pre-tool-use.ts
Comment thread plugins/gatekeeper/src/pre-tool-use.test.ts Outdated
Comment thread plugins/gatekeeper/.gitignore
Comment thread plugins/gatekeeper/hooks/hooks.json Outdated
- Add command chaining/substitution detection before DENY/ALLOW checks
- Remove exec/x from package manager allowlist (arbitrary code execution risk)
- Improve isGitPushNonForce to detect combined short flags (e.g., -vf)
- Add rm -rf /* to DENY_RULES for root wildcard deletion
- Fix .gitignore to also unignore dist/** contents
- Align AI agent prompt with documented non-force-push policy
- Update tests for all security changes

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 5 files (changes from recent commits).

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="plugins/gatekeeper/src/pre-tool-use.ts">

<violation number="1" location="plugins/gatekeeper/src/pre-tool-use.ts:63">
P2: The regex `\s-[^\s]*f` matches any flag containing `f`, not just short `-f`. This causes false positives for safe flags like `--follow-tags` and `--no-verify`, preventing `git push --follow-tags` from being auto-approved. Use `\s-(?!-)[^\s]*f` to restrict matching to single-dash flags only.</violation>

<violation number="2" location="plugins/gatekeeper/src/pre-tool-use.ts:95">
P0: Security bypass: the command chaining check (step 0) runs before the DENY check (step 1), so appending `;`, `&&`, `|`, etc. to a destructive command like `rm -rf /` downgrades it from "blocked" to "passthrough." Move the DENY check before the chaining check so known-destructive patterns are always blocked.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread plugins/gatekeeper/src/pre-tool-use.ts Outdated
Comment thread plugins/gatekeeper/src/pre-tool-use.ts Outdated

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 1 file (changes from recent commits).

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="plugins/gatekeeper/hooks/hooks.json">

<violation number="1" location="plugins/gatekeeper/hooks/hooks.json:23">
P1: Downgrading the security review agent from `opus` to `haiku` significantly weakens Layer 2 protection. This agent is the last line of defense for unrecognized commands and is explicitly tasked with detecting obfuscated commands. Haiku's weaker reasoning makes it more susceptible to adversarial inputs (e.g., chained commands hiding destructive operations via `;`, `&&`, `$(...)`) and less reliable at catching nuanced security risks. Consider keeping `opus` (or at least `sonnet`) for this security-critical role, or adding explicit examples of obfuscation patterns to the prompt to compensate.

(Based on your team's feedback about checking for command separators and subshell bypasses before auto-approving.) [FEEDBACK_USED]</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread plugins/gatekeeper/hooks/hooks.json Outdated
- Replace permissive auto-approve prompt with attack-pattern-focused prompt
- Add command chaining analysis guidance (pattern #7)
- Add project-scope vs system-scope distinction
- Upgrade PermissionRequest agent model to opus per Claude Code team recommendation
- Move DENY check before command chaining detection so destructive
  commands like `rm -rf / ; echo` are still blocked
- Fix isGitPushNonForce regex to use negative lookahead (?!-) to
  exclude long flags like --follow-tags and --no-verify from false
  positive force detection
- Add tests for deny-before-chaining priority and git push edge cases
@amondnet amondnet merged commit 95fa45e into main Feb 10, 2026
6 checks passed
@amondnet amondnet deleted the feat/gatekeeper-plugin branch March 4, 2026 11:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant