secrets-scanner — GitHub Copilot hook: catch leaked secrets
Scans the files a Copilot coding agent touched during a session for leaked keys and credentials before they get committed. Useful when the agent edits code fast.
.claude/settings.jsonWhat secrets-scanner does
The hook fires on sessionEnd, at the close of a GitHub Copilot coding agent session. It collects modified files with git diff, drops binaries and lock files, then runs each line against patterns for known secrets: AWS, GCP and Azure credentials, GitHub, npm, Slack and Stripe tokens, RSA and OpenSSH private keys, connection strings for PostgreSQL, MongoDB, MySQL, Redis and MSSQL, JWTs, and internal IPs with ports. That covers more than twenty categories.
SCAN_MODE picks the behaviour. warn only logs findings, while block exits non-zero so the agent stops before committing. SCAN_SCOPE chooses between diff and staged. Values that look like placeholders such as example, changeme or your_ are skipped, and known false positives go into SECRETS_ALLOWLIST. Scan events land in logs/copilot/secrets/scan.log as JSON Lines, with matches truncated so the log does not re-expose the secret.
No dependencies: the script leans on grep, file and git. Setup is manual — copy the folder into .github/hooks/, make the script executable, create the log directory and add it to .gitignore. If you pair it with the Session Auto-Commit hook, order matters: the scanner has to run first, otherwise the commit happens before the check. In that pairing you need SCAN_MODE=block for the block to mean anything.
What it helps with
- catch an AWS key that slipped into a modified file
- stop a commit while a GitHub token sits in the code
- filter out placeholders so false positives do not pile up
- keep an audit trail of findings in JSON Lines
- prevent auto-commit when a secret is detected
Example prompts for the agent
- Turn on secrets-scanner in block mode so the agent cannot commit secrets
- Set SCAN_SCOPE=staged and scan only the files in the index
- Add test_key_123 to SECRETS_ALLOWLIST, that one is a false positive
How to install secrets-scanner
Manually: put the files in place
.claude/settings.jsonThe hooks block: event (PreToolUse, PostToolUse, Stop…) → command. Personal ones go to ~/.claude/settings.json
Step by step, with commands for each platform: Claude Code hooks: what they are, where to configure them, how to block a risky command
Questions about secrets-scanner
How do I install secrets-scanner in GitHub Copilot?
Copy the hook folder into your repository with cp -r hooks/secrets-scanner .github/hooks/, then make the script executable: chmod +x .github/hooks/secrets-scanner/scan-secrets.sh. Create the log directory and add it to .gitignore with mkdir -p logs/copilot/secrets and echo "logs/" >> .gitignore. Finally commit the hook configuration to your default branch.
What does secrets-scanner do?
At the end of an agent session it scans modified files for leaked secrets: cloud credentials, platform tokens, private keys, connection strings and JWTs. Findings go to a log, and in block mode the session exits non-zero before committing.
What is the difference between warn and block?
warn logs findings and stops nothing. block exits non-zero, so the agent does not commit. You pick the mode with SCAN_MODE.
Source text
secrets-scanner · MIT
---
name: 'Secrets Scanner'
description: 'Scans files modified during a Copilot coding agent session for leaked secrets, credentials, and sensitive data'
tags: ['security', 'secrets', 'scanning', 'session-end']
---
# Secrets Scanner Hook
Scans files modified during a GitHub Copilot coding agent session for accidentally leaked secrets, credentials, API keys, and other sensitive data before they are committed.
## Overview
AI coding agents generate and modify code rapidly, which increases the risk of hardcoded secrets slipping into the codebase. This hook acts as a safety net by scanning all modified files at session end for 20+ categories of secret patterns, including:
- **Cloud credentials**: AWS access keys, GCP service account keys, Azure client secrets
- **Platform tokens**: GitHub PATs, npm tokens, Slack tokens, Stripe keys
- **Private keys**: RSA, EC, OpenSSH, PGP, DSA private key blocks
- **Connection strings**: Database URIs (PostgreSQL, MongoDB, MySQL, Redis, MSSQL)
- **Generic secrets**: API keys, passwords, bearer tokens, JWTs
- **Internal infrastructure**: Private IP addresses with ports
## Features
- **Two scan modes**: `warn` (log only) or `block` (exit non-zero to prevent commit)
- **Two scan scopes**: `diff` (modified files vs HEAD) or `staged` (git-staged files only)
- **Smart filtering**: Skips binary files, lock files, and placeholder/example values
- **Allowlist support**: Exclude known false positives via `SECRETS_ALLOWLIST`
- **Structured logging**: JSON Lines output for integration with monitoring tools
- **Redacted output**: Findings are truncated in logs to avoid re-exposing secrets
- **Zero dependencies**: Uses only standard Unix tools (`grep`, `file`, `git`)
## Installation
1. Copy the hook folder to your repository:
```bash
cp -r hooks/secrets-scanner .github/hooks/
```
2. Ensure the script is executable:
```bash
chmod +x .github/hooks/secrets-scanner/scan-secrets.sh
```
3. Create the logs directory and add it to `.gitignore`:
```bash
mkdir -p logs/copilot/secrets
echo "logs/" >> .gitignore
```
4. Commit the hook configuration to your repository's default branch.
## Configuration
The hook is configured in `hooks.json` to run on the `sessionEnd` event:
```json
{
"version": 1,
"hooks": {
"sessionEnd": [
{
"type": "command",
"bash": ".github/hooks/secrets-scanner/scan-secrets.sh",
"cwd": ".",
"env": {
"SCAN_MODE": "warn",
"SCAN_SCOPE": "diff"
},
"timeoutSec": 30
}
]
}
}
```
### Environment Variables
| Variable | Values | Default | Description |
|----------|--------|---------|-------------|
| `SCAN_MODE` | `warn`, `block` | `warn` | `warn` logs findings only; `block` exits non-zero to prevent auto-commit |
| `SCAN_SCOPE` | `diff`, `staged` | `diff` | `diff` scans uncommitted changes vs HEAD; `staged` scans only staged files |
| `SKIP_SECRETS_SCAN` | `true` | unset | Disable the scanner entirely |
| `SECRETS_LOG_DIR` | path | `logs/copilot/secrets` | Directory where scan logs are written |
| `SECRETS_ALLOWLIST` | comma-separated | unset | Patterns to ignore (e.g., `test_key_123,example.com`) |
## How It Works
1. When a Copilot coding agent session ends, the hook executes
2. Collects all modified files using `git diff` (respects the configured scope)
3. Filters out binary files and lock files
4. Scans each text file line-by-line against 20+ regex patterns for known secret formats
5. Skips matches that look like placeholders (e.g., values containing `example`, `changeme`, `your_`)
6. Checks matches against the allowlist if configured
7. Reports findings with file path, line number, pattern name, and severity
8. Writes a structured JSON log entry for audit purposes
9. In `block` mode, exits non-zero to signal the agent to stop before committing
## Detected Secret Patterns
| Pattern | Severity | Example Match |
|---------|----------|---------------|
| `AWS_ACCESS_KEY` | critical | `AKIAIOSFODNN7EXAMPLE` |
| `AWS_SECRET_KEY` | critical | `aws_secret_access_key = wJalr...` |
| `GCP_SERVICE_ACCOUNT` | critical | `"type": "service_account"` |
| `GCP_API_KEY` | high | `AIzaSyC...` |
| `AZURE_CLIENT_SECRET` | critical | `azure_client_secret = ...` |
| `GITHUB_PAT` | critical | `ghp_xxxxxxxxxxxx...` |
| `GITHUB_FINE_GRAINED_PAT` | critical | `github_pat_...` |
| `PRIVATE_KEY` | critical | `-----BEGIN RSA PRIVATE KEY-----` |
| `GENERIC_SECRET` | high | `api_key = "sk-..."` |
| `CONNECTION_STRING` | high | `postgresql://user:pass@host/db` |
| `SLACK_TOKEN` | high | `xoxb-...` |
| `STRIPE_SECRET_KEY` | critical | `sk_live_...` |
| `NPM_TOKEN` | high | `npm_...` |
| `JWT_TOKEN` | medium | `eyJhbGci...` |
| `INTERNAL_IP_PORT` | medium | `192.168.1.1:8080` |
See the full list in `scan-secrets.sh`.
## Example Output
### Clean scan
```
🔍 Scanning 5 modified file(s) for secrets...
✅ No secrets detected in 5 scanned file(s)
```
### Findings detected (warn mode)
```
🔍 Scanning 3 modified file(s) for secrets...
⚠️ Found 2 potential secret(s) in modified files:
FILE LINE PATTERN SEVERITY
---- ---- ------- --------
src/config.ts 12 GITHUB_PAT critical
.env.local 3 CONNECTION_STRING high
💡 Review the findings above. Set SCAN_MODE=block to prevent commits with secrets.
```
### Findings detected (block mode)
```
🔍 Scanning 3 modified file(s) for secrets...
⚠️ Found 1 potential secret(s) in modified files:
FILE LINE PATTERN SEVERITY
---- ---- ------- --------
lib/auth.py 45 AWS_ACCESS_KEY critical
🚫 Session blocked: resolve the findings above before committing.
Set SCAN_MODE=warn to log without blocking, or add patterns to SECRETS_ALLOWLIST.
```
## Log Format
Scan events are written to `logs/copilot/secrets/scan.log` in JSON Lines format:
```json
{"timestamp":"2026-03-13T10:30:00Z","event":"secrets_found","mode":"warn","scope":"diff","files_scanned":3,"finding_count":2,"findings":[{"file":"src/config.ts","line":12,"pattern":"GITHUB_PAT","severity":"critical","match":"ghp_...xyz1"}]}
```
```json
{"timestamp":"2026-03-13T10:30:00Z","event":"scan_complete","mode":"warn","scope":"diff","status":"clean","files_scanned":5}
```
## Pairing with Other Hooks
This hook pairs well with the **Session Auto-Commit** hook. When both are installed, order them so that `secrets-scanner` runs first:
1. Secrets scanner runs at `sessionEnd`, catches leaked secrets
2. Auto-commit runs at `sessionEnd`, only commits if all previous hooks pass
Set `SCAN_MODE=block` to prevent auto-commit when secrets are detected.
## Customization
- **Add custom patterns**: Edit the `PATTERNS` array in `scan-secrets.sh` to add project-specific secret formats
- **Adjust sensitivity**: Change severity levels or remove patterns that generate false positives
- **Allowlist known values**: Use `SECRETS_ALLOWLIST` for test fixtures or known safe patterns
- **Change log location**: Set `SECRETS_LOG_DIR` to route logs to your preferred directory
## Disabling
To temporarily disable the scanner:
- Set `SKIP_SECRETS_SCAN=true` in the hook environment
- Or remove the `sessionEnd` entry from `hooks.json`
## Limitations
- Pattern-based detection; does not perform entropy analysis or contextual validation
- May produce false positives for test fixtures or example code (use the allowlist to suppress these)
- Scans only text files; binary secrets (keystores, certificates in DER format) are not detected
- Requires `git` to be available in the execution environment
```json
{
"version": 1,
"hooks": {
"sessionEnd": [
{
"type": "command",
"bash": ".github/hooks/secrets-scanner/scan-secrets.sh",
"cwd": ".",
"env": {
"SCAN_MODE": "warn",
"SCAN_SCOPE": "diff"
},
"timeoutSec": 30
}
]
}
}
```
© github · MIT · github/awesome-copilot