This is the complete technical guide for Gate v2. It covers every component, how to use it, and how to extend it.
Gate is a zero-config secret scanner that runs as a CLI tool. It installs as a git hook and scans files for leaked secrets, API keys, PII, and other sensitive data before they reach your repository.
gate/
├── bin/gate.js # CLI entry point
├── src/
│ └── cli/ # Scanner modules (pure JS, no build needed)
│ ├── scanner.js # Core scanning engine
│ ├── rules.js # 80 built-in rules + rules.json loader
│ ├── config.js # .gaterc configuration loader
│ ├── ignore.js # .gateignore pattern matching
│ ├── output.js # Terminal formatting (color, CI, SARIF)
│ ├── audit.js # Local audit log with integrity chain
│ ├── installer.js # Git hook installer (pre-commit + pre-push)
│ ├── init.js # Interactive project setup
│ ├── status.js # Health check display
│ ├── remediation.js # Fix guidance per secret type
│ ├── updater.js # Self-update checker
│ └── vault.js # Local AES-256-GCM encryption
├── rules/ # FORTRESS rule engine (68 detection rules)
│ ├── rules.json # Detection patterns (cryptographically signed)
│ ├── rules.json.sig # HMAC-SHA256 signature
│ └── fortress.js # Rule signing, verification, testing CLI
├── github-action/ # GitHub Action (separate, for Marketplace)
├── test/ # Integration tests
└── src/cli/__tests__/ # Unit tests
Gate runs entirely on your local machine. There is no database, no Redis, no API server, no dashboard. Everything happens in the CLI:
| Command | What it does |
|---|---|
gate |
Install hook (first run) or show status |
gate scan |
Scan staged files for secrets |
gate scan --all |
Scan all tracked files |
gate scan --verify |
Scan and check if credentials are live |
gate scan --interactive |
Scan and enter interactive remediation TUI |
gate scan --history N |
Scan last N commits for secrets in history |
gate scan --format sarif |
Emit SARIF 2.1.0 for GitHub Code Scanning |
gate fix |
Auto-remediate all findings (extract to .env) |
gate fix --dry-run |
Preview fixes without changing files |
gate fix --undo |
Revert the most recent fix |
gate report |
Generate Markdown compliance report |
gate report --format html |
Generate HTML compliance report |
gate report --incident <id> |
Generate incident report for a specific incident |
gate purge |
Generate git-filter-repo cleanup script |
gate init |
Set up Gate for a project |
gate status |
Show installation health |
gate vault |
Encrypt/decrypt secrets locally |
gate audit |
View or query the audit log |
gate install |
Install pre-commit hook |
gate uninstall |
Remove pre-commit hook |
gate update |
Check for and install updates |
gate version |
Show version |
- Node.js >= 18 (tested on 18, 20, 22, 25)
That's it. No PostgreSQL, no Redis, no other services.
npm install -g @penumbraforge/gatecd your-project
npx @penumbraforge/gategit clone https://github.com/penumbraforge/gate.git
cd gate
npm install
npm link # makes `gate` available globallyWhen you run gate in a git repository for the first time, it automatically installs the pre-commit hook:
cd your-project
gate
# -> "Pre-commit hook installed at .git/hooks/pre-commit"On subsequent runs, gate shows the status display.
- File Input — Reads file content line by line
- Pattern Matching — Tests each line against 80 built-in regex rules + 68 rules from
rules/rules.json - Entropy Analysis — Calculates Shannon entropy on suspicious tokens (threshold: 4.8 bits/char by default)
- Ignore Filtering — Checks
.gateignorepatterns, rule-scoped suppressions, and inlinegate-ignorecomments - False Positive Filtering — Skips known safe patterns (test fixtures, example values, common variable names)
- Result Aggregation — Groups findings by file, severity (critical/high/medium/low)
The rules/ directory contains the detection rules:
rules.json— 281 detection patterns, cryptographically signedfortress.js— Rule signing, verification, and testing CLIrules.json.sig— HMAC-SHA256 signature for tamper detection
Rules cover:
- Cloud providers — AWS, GCP, Azure access keys, service accounts, SAS tokens
- Code platforms — GitHub, GitLab, Bitbucket tokens and OAuth credentials
- Communication — Slack, Discord, Telegram, Twilio tokens
- Payment — Stripe, PayPal, Square API keys
- Databases — PostgreSQL, MySQL, MongoDB, Redis connection strings
- Private keys — RSA, DSA, EC, PGP, SSH keys
- PII — SSN, credit cards, passport numbers, email addresses
- Infrastructure — Kubernetes, Docker, Terraform, Vault secrets
- SaaS — SendGrid, Mailgun, Algolia, Firebase, Supabase, and dozens more
Gate supports three output formats:
gate scan # text (default) — colored terminal output
gate scan --format json # JSON — structured output for tooling
gate scan --format sarif # SARIF — for GitHub Code Scanning / IDE integrationGate automatically detects CI environments and emits platform-specific annotations:
- GitHub Actions —
::error file=...annotations - GitLab CI —
GL-SAST-REPORTcompatible output
Create a .gaterc file in your project root to customize Gate's behavior. Supports YAML or JSON.
# Entropy threshold for high-entropy string detection
# Higher = fewer false positives, lower = more sensitive
entropy_threshold: 4.8
# Verify rule signatures on load
verify: true
# Which git hooks to install
hooks:
- pre-commit
- pre-push
# Override severity levels for specific rules
severity:
high-entropy-string: low
# Custom detection rules
rules:
- id: internal-api-key
name: Internal API Key
pattern: "INTERNAL_KEY_[A-Za-z0-9]{32}"
severity: high
remediation: Rotate this key in the internal dashboard
# Output settings
output:
format: text # text, json, sarif
color: auto # auto, true, false
context_lines: 2 # lines of code context around findings| Option | Default | Description |
|---|---|---|
entropy_threshold |
4.8 |
Shannon entropy threshold for high-entropy detection |
verify |
true |
Verify HMAC signature on rules.json |
hooks |
['pre-commit'] |
Git hooks to install (pre-commit, pre-push) |
severity |
{} |
Override severity for rule IDs |
rules |
[] |
Custom detection rules (id, pattern, severity required) |
output.format |
text |
Output format: text, json, sarif |
output.color |
auto |
Color output: auto, true, false |
output.context_lines |
2 |
Lines of code context around each finding |
Create a .gateignore file to suppress false positives. Supports glob patterns and rule-scoped suppression.
# Ignore entire directories
node_modules/**
dist/**
test/fixtures/**
# Ignore specific files
docs/examples/fake-credentials.md
# Rule-scoped: only ignore a specific rule in specific files
[rule:high-entropy-string] src/crypto/constants.js
[rule:aws-access-key] test/mocks/**| Pattern | Effect |
|---|---|
path/to/file |
Ignore all findings in this file |
dir/** |
Ignore all findings in this directory recursively |
*.min.js |
Ignore all findings in minified JS files |
[rule:RULE-ID] path |
Ignore only the specified rule in matching files |
You can also suppress findings inline in your source code:
const EXAMPLE_KEY = 'sk_test_abc123'; // gate-ignore: test fixture
const API_URL = process.env.API_URL; // gate-ignoreThe scanner recognizes // gate-ignore and /* gate-ignore */ comments. Optionally include a reason after the colon.
Scan files for secrets.
gate scan # scan staged files (pre-commit mode)
gate scan --all # scan all tracked files
gate scan file1.js file2.py # scan specific files
gate scan --format json # JSON output
gate scan --format sarif # SARIF output
gate scan --no-color # disable color
gate scan --entropy-threshold 5.0 # custom entropy thresholdExit codes:
0— no findings1— findings detected (commit should be blocked)
Interactive project setup. Detects your stack, creates .gateignore, installs hook, updates .gitignore.
gate init
# -> detected: node
# -> .gateignore created
# -> .gitignore updated (env patterns added)
# -> pre-commit hook installedSupported stack detection: Node.js, Python, Go, Ruby, Rust, Java, .NET.
Show Gate installation health.
gate statusDisplays:
- Hook installation status (pre-commit, pre-push)
- Configuration source (defaults or .gaterc)
- Ignore patterns loaded
- Rule count
- Last scan info
- Audit log summary
Local AES-256-GCM encryption for secrets.
gate vault keygen # generate encryption key (~/.gate/vault.key)
gate vault keygen --force # regenerate key (overwrites existing)
gate vault encrypt "my-secret" # encrypt a value
gate vault decrypt "VAULT:..." # decrypt a vault blob
gate vault env .env # encrypt all values in a .env fileVault key is stored at ~/.gate/vault.key. Encrypted values use the format VAULT:iv:ciphertext:tag.
View and query the local audit log.
gate audit # show recent entries
gate audit --since 7d # last 7 days
gate audit --since 2w # last 2 weeks
gate audit --stats # aggregate statistics
gate audit --export json # export full log as JSON
gate audit --verify # verify integrity chain
gate audit --clear # delete audit log (requires confirmation)Manage git hooks.
gate install # install pre-commit hook
gate uninstall # remove pre-commit hookCheck for updates and install them.
gate update # check and install update
gate version # show version + update checkEvery scan is logged to ~/.gate/audit.jsonl with:
- Timestamp, commit hash, files scanned
- Findings with severity
- User decision (approved/reported/bypassed)
- SHA-256 integrity chain (each entry hashes the previous)
The integrity chain makes the audit log tamper-detectable. Run gate audit --verify to check it.
The GitHub Action lives in github-action/ and is published separately to the GitHub Marketplace.
- Checks out the repo
- Runs the Gate scanner on changed files
- Reports findings as PR comments
- Can block merging (
failure-mode: block) or just warn (failure-mode: warn) - Optionally sends Slack notifications
# .github/workflows/gate.yml
name: Gate Security
on: [pull_request, push]
jobs:
gate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: penumbraforge/gate@v2
with:
mode: enforce # or 'report'
failure-mode: block # or 'warn'
slack-webhook: ${{ secrets.SLACK_WEBHOOK }}| Input | Default | Description |
|---|---|---|
mode |
report |
enforce blocks on findings, report just logs |
verify |
false |
Run credential verification for supported providers |
format |
text |
Output format: text, json, sarif |
fail-on |
high |
Minimum severity to fail: critical, high, medium, low |
failure-mode |
derived | block fails CI, warn passes but alerts (derived from mode if omitted) |
slack-webhook |
--- | Slack webhook URL for notifications |
github-token |
${{ github.token }} |
For PR comments and SARIF upload |
| Output | Description |
|---|---|
findings-count |
Number of findings detected |
blocked |
Whether the commit was blocked |
scan-report |
Full JSON scan report |
npm test # all tests (386+ tests, 18 suites)
npm run test:cli # CLI tests only
npx jest --watch # watch mode
npx jest --no-coverage # skip coverage thresholds| Suite | Location | Tests |
|---|---|---|
| Scanner integration | test/scanner.test.js |
~100 |
| Scanner unit | src/cli/__tests__/scanner.test.js |
~30 |
| Rules | src/cli/__tests__/rules.test.js |
~20 |
| Rules expansion | src/cli/__tests__/rules-expansion.test.js |
~20 |
| Config | src/cli/__tests__/config.test.js |
~15 |
| Ignore | src/cli/__tests__/ignore.test.js |
~15 |
| Output | src/cli/__tests__/output.test.js |
~15 |
| Init | src/cli/__tests__/init.test.js |
~15 |
| Status | src/cli/__tests__/status.test.js |
~15 |
| Installer | src/cli/__tests__/installer.test.js |
~15 |
| Audit | src/cli/__tests__/audit.test.js |
~15 |
| Self-scan | src/cli/__tests__/self-scan.test.js |
~5 |
| Exposure | src/cli/__tests__/exposure.test.js |
~20 |
| Verify | src/cli/__tests__/verify.test.js |
~20 |
| Fixer | src/cli/__tests__/fixer.test.js |
~25 |
| Interactive | src/cli/__tests__/interactive.test.js |
~15 |
| Incident | src/cli/__tests__/incident.test.js |
~20 |
| Reporter | src/cli/__tests__/reporter.test.js |
~20 |
| History | src/cli/__tests__/history.test.js |
~20 |
| Module | Branches | Functions | Lines | Statements |
|---|---|---|---|---|
src/cli/rules.js |
100% | 100% | 100% | 100% |
src/cli/scanner.js |
75% | 75% | 80% | 80% |
| Global | 70% | 70% | 75% | 75% |
| Layer | Protection |
|---|---|
| Rules | HMAC-SHA256 signed, versioned, tamper-detectable |
| Audit trail | SHA-256 integrity chain, append-only |
| Vault | AES-256-GCM encryption for local secrets |
| Scanner | No eval, no dynamic requires, no shell exec |
| Dependencies | Single runtime dependency (js-yaml) |
| Updates | Version check against npm registry |
| Path | Purpose |
|---|---|
bin/gate.js |
CLI entry point — parses commands, dispatches to handlers |
src/cli/scanner.js |
Core scanning engine — pattern matching + entropy analysis |
src/cli/rules.js |
80 built-in rules + rules.json loader with signature verification |
src/cli/config.js |
.gaterc loader — YAML/JSON config with stack detection |
src/cli/ignore.js |
.gateignore loader — glob patterns, rule-scoped suppression, inline ignore |
src/cli/output.js |
Terminal output — color, CI annotation, SARIF builder |
src/cli/audit.js |
Local audit log (append, query, export, verify, clear) |
src/cli/installer.js |
Git hook installer/uninstaller (pre-commit + pre-push) |
src/cli/init.js |
Interactive setup — stack detection, .gateignore generation |
src/cli/status.js |
Health check — hook status, config, rules, last scan |
src/cli/remediation.js |
Per-secret-type fix guidance with links |
src/cli/updater.js |
Self-update checker (npm registry) |
src/cli/vault.js |
AES-256-GCM keygen, encrypt, decrypt, env-file encryption |
src/cli/verify.js |
Credential verification — read-only API calls per provider |
src/cli/fixer.js |
Auto-fix engine — extract to .env, rewrite source (9 languages) |
src/cli/interactive.js |
Interactive remediation TUI — single-keypress actions |
src/cli/incident.js |
Incident response — 5-step guided workflow for PUSHED secrets |
src/cli/reporter.js |
Report generation — Markdown, HTML, SARIF 2.1.0, JSON |
src/cli/history.js |
Git history scanner + git-filter-repo purge script generator |
src/cli/exposure.js |
Exposure assessment — LOCAL / COMMITTED / PUSHED / UNKNOWN |
rules/rules.json |
281 detection patterns (signed) |
rules/fortress.js |
Rule engine CLI — sign, verify, test rules |
rules/rules.json.sig |
HMAC-SHA256 signature for rules.json |
github-action/action.js |
GitHub Action entry point |
github-action/action.yml |
Action metadata for Marketplace |
Gate can make read-only API calls to each provider's own endpoint to confirm whether a detected secret is still active.
gate scan --verify # scan + verify detected credentials
gate scan --all --verify # full-repo scan with verification- Each finding is matched to a provider (AWS, GitHub, Stripe, GCP, etc.)
- A read-only API call is made to that provider's identity endpoint (e.g.
GET https://api.github.com/userwith the token asAuthorization: Bearer) - A
401or403means the credential is revoked — low priority - A
200or2xxmeans the credential is live — critical - Results are cached in
~/.gate/verify-cache.jsonfor 1 hour to avoid redundant API calls
- Per-provider timeout: 2 seconds
- Total verification budget: 5 seconds across all findings
- If the budget is exceeded, remaining findings are marked
UNVERIFIED - Verification results are shown inline next to each finding:
[LIVE],[REVOKED],[UNVERIFIED]
Verification is opt-in. It only runs when --verify is passed explicitly, or when verify: true is set in .gaterc (and Gate is not running as a pre-commit hook, to avoid slowing commits).
Gate can automatically extract secrets from source files into a .env file and rewrite the source code to use environment variable references.
gate fix # fix all current findings
gate fix --dry-run # preview changes without writing files
gate fix --undo # revert the most recent fix- Gate scans staged files for secrets
- For each finding, it identifies the secret value and maps it to a well-known env var name (e.g.
STRIPE_SECRET_KEY,DATABASE_URL,OPENAI_API_KEY) - The secret is appended to
.env(created if absent) - The source line is rewritten to reference the env var instead
- A snapshot is saved to
~/.gate/snapshots/for undo support
| Language | Extensions | Env Reference |
|---|---|---|
| JavaScript / TypeScript | .js, .jsx, .mjs, .cjs, .ts, .tsx |
process.env.VAR_NAME |
| Python | .py |
os.environ['VAR_NAME'] (adds import os if absent) |
| Go | .go |
os.Getenv("VAR_NAME") (adds "os" import if absent) |
| Ruby | .rb |
ENV['VAR_NAME'] |
| Java | .java |
System.getenv("VAR_NAME") |
| YAML | .yml, .yaml |
${VAR_NAME} |
| Terraform | .tf |
var.VAR_NAME |
| JSON | .json |
__ENV_VAR_NAME__ (placeholder) |
| Dockerfile | Dockerfile |
$VAR_NAME (ARG/ENV block) |
Use --dry-run to preview what would change without touching any files:
gate fix --dry-run
# -> Dry run: 3 finding(s) would be fixed, 1 skipped.
# -> Would rewrite: src/config.js line 12
# -> Would add to .env: STRIPE_SECRET_KEY=sk_live_...Snapshots are stored per-fix in ~/.gate/snapshots/. The --undo flag restores the most recent snapshot:
gate fix --undo
# -> Reverted fix from 2026-03-21T14:22:00ZThe interactive TUI presents findings one at a time and accepts single-keypress commands. It uses Node's built-in readline raw mode — no external dependencies.
gate scan --interactive # scan and enter interactive mode
gate scan --all --interactive # full-repo scan, then interactive- Gate scans files and collects all findings
- Each finding is shown with file path, line number, matched text, rule name, and severity
- The exposure level (LOCAL / COMMITTED / PUSHED) is shown alongside
- A single keypress selects the action
| Key | Action |
|---|---|
f |
Fix — extract to .env, rewrite source line |
i |
Ignore — add inline // gate-ignore comment |
v |
Vault — encrypt with gate vault and replace in source |
c |
Copy — copy secret value to clipboard |
s |
Skip — leave this finding unchanged (it will appear next scan) |
q |
Quit — exit interactive mode |
Ctrl+C |
Abort — exit immediately |
When running in a non-TTY environment (CI, pipes), interactive mode falls back to a no-op and prints the findings list.
When a secret has been pushed to a remote repository (exposure level: PUSHED), Gate triggers a 5-step guided incident response workflow.
The workflow runs automatically after interactive mode if the exposure is PUSHED, or can be triggered manually:
# Triggered automatically in interactive mode for PUSHED findings
# Steps are shown one at a time with provider-specific instructions| Step | Name | What happens |
|---|---|---|
| 1 | ROTATE | Provider-specific instructions to revoke and reissue the credential. Includes CLI commands and web console links. |
| 2 | AUDIT | Instructions to review access logs for unauthorized use during the exposure window. |
| 3 | CLEAN CODE | Calls the fixer to extract the secret from source files and rewrite to env var reference. |
| 4 | SCRUB HISTORY | Generates a git-filter-repo script to remove the secret from all git history. |
| 5 | DOCUMENT | Creates a formal incident record in ~/.gate/incidents/ and generates a Markdown report. |
Provider-specific guidance is available for: AWS, GitHub, Stripe, GCP, Azure, Heroku, Slack, npm, PyPI, Docker Hub, Datadog, Twilio, SendGrid, and generic providers.
Incidents are saved as JSON to ~/.gate/incidents/<id>.json. Use gate report --incident <id> to generate a Markdown report from an incident record.
Gate can generate compliance reports from the audit log or from a specific incident.
gate report # Markdown report to gate-report-YYYY-MM-DD.md
gate report --format html # HTML report to gate-report-YYYY-MM-DD.html
gate report --incident <id> # Incident report to gate-incident-<id>.mdEach finding in a report includes compliance framework annotations:
| Framework | Coverage |
|---|---|
| OWASP Top 10 | A02:2021, A05:2021, A07:2021, A08:2021 |
| NIST 800-53 | SC-12, SC-17, IA-5 |
| CIS Controls | CIS 5.2, CIS 14.4 |
| SOC 2 | CC6.1, CC6.2, CC9.2 |
Mappings are defined per rule ID in src/cli/reporter.js.
A compliance report includes:
- Executive summary (findings by severity, files scanned, date range)
- Finding detail table (file, line, rule, severity, compliance mapping)
- Remediation status (fixed / pending / ignored)
- Audit trail summary
Gate emits SARIF 2.1.0 for integration with GitHub Advanced Security and IDE plugins.
gate scan --format sarif # print SARIF to stdout
gate scan --format sarif > results.sarif # save to fileUpload SARIF results as a Code Scanning artifact:
# .github/workflows/gate.yml
- name: Run Gate
run: gate scan --all --format sarif > gate.sarif
- name: Upload SARIF
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: gate.sarifFindings will appear in the Security tab of your repository as Code Scanning alerts.
Gate's SARIF output includes:
runs[0].tool.driver.rules— one rule entry per Gate rule (id, name, shortDescription, helpUri)runs[0].results— one result per finding (ruleId, message, locations with region)- Severity mapped to SARIF level: critical/high →
error, medium →warning, low →note
Gate can scan past commits to find secrets that were introduced (and possibly later removed) from your codebase.
gate scan --history 50 # scan last 50 commits
gate scan --history 100 # scan last 100 commitsgit logretrieves the last N commits in order- For each commit,
git diff <hash>^..<hash>extracts added lines - Added lines are scanned with the same pattern+entropy engine as regular scans
- Findings include the commit hash, date, author, and commit message
- Duplicates across commits are deduplicated by (file, line content, rule)
For root commits (no parent), git diff-tree --root is used.
Scanned 50 commits — 2 secret(s) found in history:
[abc1234] 2026-01-15 alice@example.com "initial config"
src/config.js STRIPE_SECRET_KEY stripe-live-secret critical
[def5678] 2026-02-03 bob@example.com "add payment service"
src/payment.js AWS_ACCESS_KEY_ID aws-access-key-id critical
After identifying secrets in history, use gate purge to generate the cleanup script (see below).
When secrets exist in git history, they must be removed from all commits — not just the current files. gate purge automates this by generating a git-filter-repo script.
gate purge # scan history (default: 50 commits) and generate script- Runs history scan to find secrets in past commits
- For each affected file, generates a
git-filter-repo --path-glob+--replace-textcommand - The script is saved to
gate-purge-<timestamp>.sh - You review and run the script manually (it is not executed automatically)
# Install git-filter-repo first
pip install git-filter-repo
# Review the generated script
cat gate-purge-<timestamp>.sh
# Run it (DESTRUCTIVE — rewrites git history)
bash gate-purge-<timestamp>.sh
# Force-push rewritten history (coordinate with your team first)
git push --force-with-leaseNote: Rewriting git history is destructive and requires all collaborators to re-clone. Coordinate with your team and rotate the leaked credentials before running the purge script.
Gate requires a git repository. Initialize one first:
git init
gateMake sure the hook is installed and executable:
gate status # check hook status
gate install # reinstall if needed
ls -la .git/hooks/pre-commit- Create a
.gateignorefile with patterns for your project - Use rule-scoped ignores:
[rule:high-entropy-string] path/to/file.js - Use inline comments:
// gate-ignore: reason - Adjust entropy threshold:
gate scan --entropy-threshold 5.0 - Run
gate initto auto-detect your stack and generate a starter.gateignore
If Gate's own source triggers findings, make sure .gateignore is present at the project root. Run:
gate scan --allThe .gateignore in the Gate repo suppresses known false positives from rule definitions and test fixtures.