guides

Gemini CLI

Integrate sus with Gemini CLI hooks to automatically scan packages installed by AI agents

Gemini CLI's hooks system lets you intercept and customize agent behavior at specific points in the agentic loop. By using the BeforeTool hook, you can automatically route all package installations through sus for security scanning.

Why Use Hooks?

When AI agents install packages autonomously, they don't verify package integrity or check for known vulnerabilities. This makes them vulnerable to:

  • Typosquatting - installing lodashs instead of lodash
  • Supply chain attacks - compromised packages like event-stream
  • Malicious install scripts - packages that execute code during installation

With sus hooks, every npm install, yarn add, pnpm add, or bun add command is intercepted and routed through sus first.

Prerequisites

Setup

1. Create the hooks configuration

Create .gemini/settings.json in your project root:

JSON
{
  "hooks": {
    "BeforeTool": [
      {
        "matcher": "shell|bash|run_shell_command",
        "hooks": [
          {
            "name": "sus-gateway",
            "type": "command",
            "command": "$GEMINI_PROJECT_DIR/.gemini/hooks/sus-gateway.sh",
            "timeout": 5000
          }
        ]
      }
    ]
  }
}

The matcher is a regex that matches shell-related tool names, ensuring the hook only runs for shell commands.

2. Create the hook script

Create .gemini/hooks/sus-gateway.sh:

Bash
#!/bin/bash
input=$(cat)
cmd=$(echo "$input" | jq -r '.input.command // .input.args.command // empty')
 
# Match install commands with packages
if [[ "$cmd" =~ ^(npm\ (i|install|add)|yarn\ add|pnpm\ (add|i)|bun\ (add|i)|pip\ install|cargo\ add)\ (.+)$ ]]; then
  pkg="${BASH_REMATCH[5]}"
  jq -n --arg p "$pkg" '{decision:"block", reason:"Use `sus add \($p)` instead for security scanning."}'
elif [[ "$cmd" =~ ^(npm\ (uninstall|rm)|yarn\ remove|pnpm\ (rm|remove)|bun\ (rm|remove)|pip\ uninstall|cargo\ remove)\ (.+)$ ]]; then
  pkg="${BASH_REMATCH[5]}"
  jq -n --arg p "$pkg" '{decision:"block", reason:"Use `sus remove \($p)` instead."}'
else
  echo '{"decision":"allow"}'
fi

3. Make the script executable

Bash
chmod +x .gemini/hooks/sus-gateway.sh

Important: JSON Output Rules

Gemini CLI has strict requirements for hook output:

  • Only JSON to stdout - Your script must output only valid JSON. No echo or print statements before the JSON.
  • Use stderr for debugging - Write debug output to stderr: echo "debug" >&2
  • Exit code 0 - Return exit code 0 with decision: "block" to deny an action
  • Exit code 2 - For critical system blocks (script failures, security stops)

If stdout contains any non-JSON text, parsing fails and the hook is treated as allowing the action.

How It Works

When Gemini CLI tries to run a package install command:

100%
  1. Gemini CLI attempts npm install express
  2. Hook intercepts via BeforeTool event
  3. Hook outputs {"decision":"block", "reason":"..."}
  4. Gemini CLI follows the instruction and runs sus add express
  5. sus scans the package for vulnerabilities
  6. If safe, sus installs using your detected package manager

Command Mapping

The hook intercepts these commands and routes them through sus:

Original Commandsus Equivalent
npm install pkgsus add pkg
yarn add pkgsus add pkg
pnpm add pkgsus add pkg
bun add pkgsus add pkg
pip install pkgsus add pkg
cargo add pkgsus add pkg

Commands without specific packages (like npm install to install from package.json) are allowed through.

Testing the Integration

Ask Gemini CLI to install a package:

Text
Install the express package

You should see the hook block the command and instruct Gemini to use sus instead:

Bash
🔍 checking express@4.21.0...
 not sus
   ├─ publisher: expressjs (verified)
   ├─ downloads: 32M/week
   ├─ cves: 0
   └─ install scripts: none
📦 installed
📝 updated AGENTS.md docs index

Global Configuration

To apply sus hooks to all your projects, add the configuration to your user settings at ~/.gemini/settings.json.

For the hook script, either:

  • Place it at a fixed global path and reference it absolutely
  • Or use $GEMINI_PROJECT_DIR for project-relative paths

Managing Hooks

Gemini CLI provides commands to manage hooks without editing JSON:

Bash
# View all hooks
/hooks panel
 
# Enable/disable all hooks
/hooks enable-all
/hooks disable-all
 
# Toggle individual hooks
/hooks enable sus-gateway
/hooks disable sus-gateway

Troubleshooting

Hook not triggering

  1. Verify the settings file exists at .gemini/settings.json
  2. Check that the script is executable: chmod +x .gemini/hooks/sus-gateway.sh
  3. Verify the matcher regex matches your shell tool name
  4. Check /hooks panel to see if the hook is enabled

JSON parsing errors

If the hook isn't blocking commands, check that your script outputs only JSON:

Bash
# Test the script
echo '{"input":{"command":"npm install express"}}' | .gemini/hooks/sus-gateway.sh

Expected output (no extra text):

JSON
{"decision":"block","reason":"Use `sus add express` instead for security scanning."}

Debugging

Write debug output to stderr (not stdout):

Bash
#!/bin/bash
input=$(cat)
echo "Received: $input" >&2  # Debug to stderr
cmd=$(echo "$input" | jq -r '.input.command // empty')
echo "Command: $cmd" >&2     # Debug to stderr
 
# ... rest of script

jq not found

The script requires jq for JSON parsing. Install it:

Bash
# macOS
brew install jq
 
# Ubuntu/Debian
sudo apt-get install jq
 
# Windows (with chocolatey)
choco install jq

Next Steps