Secrets Scanning: Pre-Commit Hooks, CI Pipeline Enforcement, and Remediation

Retool's new app builder is where AI-generated code ships safely
Building apps with AI is easy. Getting them to production safely is another story.
A single exposed API key or database credential in a git commit can compromise your entire infrastructure. Automated scanners continuously trawl GitHub, GitLab, and Bitbucket for exposed secrets, and the median time between a push and a first exploitation attempt is under an hour. Despite this, most engineering organizations have no systematic secrets scanning. This guide gives you the exact setup for pre-commit scanning, CI pipeline enforcement, GitHub Advanced Security configuration, and the proper workflow for remediating secrets that are already in your repository history.
Layer 1: Pre-Commit Hooks with Gitleaks
Pre-commit scanning catches secrets before they enter git history. It runs locally on the developer's machine and provides immediate feedback without waiting for CI.
Install and configure gitleaks
macOS: brew install gitleaks. Linux: download from GitHub releases or go install github.com/gitleaks/gitleaks/v8@latest. Create .gitleaks.toml in your repository root for custom rules. The default ruleset covers 150+ secret types including AWS, GCP, GitHub, Stripe, Twilio, and generic high-entropy strings.
Add as a pre-commit hook
Using the pre-commit framework (.pre-commit-config.yaml): repos: - repo: https://github.com/gitleaks/gitleaks rev: v8.18.0 hooks: - id: gitleaks Install: pre-commit install. This runs gitleaks detect --staged before every commit. Developers who try to commit a file containing a secret see an immediate error with the file and line number.
Allowlist false positives
Some patterns generate false positives, test fixtures, example credentials in documentation, or intentionally placeholder values. Gitleaks supports inline allowlisting: add # gitleaks:allow to the end of a line to suppress detection for that specific line. For broader patterns, add to .gitleaks.toml under [allowlist]: regexes = ["EXAMPLE_API_KEY", "test_token_.*"]. Never globally allowlist real credential patterns.
Scan existing history
gitleaks detect --source . --log-opts '--all' scans the full git history of the current repository. Run this as a one-time audit on every repository before deploying the pre-commit hook, so you know what is already there. Output to JSON: gitleaks detect --report-path gitleaks-report.json --log-opts '--all'.
Layer 2: CI Pipeline Blocking
Pre-commit hooks are advisory, they can be bypassed with --no-verify. The authoritative secrets gate is your CI pipeline, which runs on every PR and cannot be bypassed by developers.
GitHub Actions: gitleaks on every PR
name: Secret Scan on: [pull_request, push] jobs: gitleaks: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: fetch-depth: 0 - uses: gitleaks/gitleaks-action@v2 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITLEAKS_LICENSE: ${{ secrets.GITLEAKS_LICENSE }} Set the job as a required status check on your default branch, PRs cannot merge until the scan passes.
TruffleHog for deeper CI scanning
TruffleHog's --verified flag actively validates found secrets against provider APIs, it only reports secrets that are still live. Add to CI: trufflehog github --repo https://github.com/{org}/{repo} --only-verified --fail. The --fail flag exits non-zero when verified secrets are found, blocking the pipeline. TruffleHog also supports scanning against a specific commit range: trufflehog git file://. --since-commit {BASE_COMMIT} --only-verified.
Block merges without a passing scan
In GitHub: Settings > Branches > Branch protection rules > Require status checks to pass before merging. Add the gitleaks or TruffleHog job as a required check. In GitLab: Settings > CI/CD > Pipelines > Require all jobs to succeed. In Bitbucket: Repository Settings > Branch permissions > Merge checks. This creates an organizational forcing function, secrets cannot reach main/master without being caught.
Scan pull request diffs, not just staged files
Configure the CI scanner to compare the PR branch against the base branch diff only, not the full history. This is faster and avoids reporting on old findings already in history. gitleaks detect --log-opts '{BASE_SHA}..{HEAD_SHA}'. For TruffleHog: trufflehog git file://. --since-commit {BASE_SHA} --branch {HEAD_SHA}.
Briefings like this, every morning before 9am.
Threat intel, active CVEs, and campaign alerts, distilled for practitioners. 50,000+ subscribers. No noise.
Layer 3: GitHub Advanced Security Secret Scanning
GitHub Advanced Security (GHAS) runs secrets scanning automatically on every push across your entire organization and integrates with provider push-protection to block commits before they are accepted.
Enable secret scanning at organization level
GitHub Organization Settings > Code security and analysis > Secret scanning > Enable for all repositories. Also enable Push protection, this blocks the push at the server side before the commit is accepted, even if the developer uses --no-verify locally. Push protection is the strongest preventive control for GitHub-hosted repositories.
Secret scanning partner patterns
GitHub GHAS secret scanning automatically detects secrets for 200+ providers and sends alerts to the affected provider for immediate revocation. When a GitHub token, AWS key, or Slack token is pushed to a GitHub repository, the provider is notified and can revoke the token before an attacker can use it. This is active for public repositories by default; GHAS extends it to private repositories.
Custom secret patterns
For internally issued tokens (internal API keys, database connection strings with company-specific patterns), add custom patterns in Organization Settings > Code security > Secret scanning > Custom patterns. Define a regex that matches your internal token format. GitHub will scan all repositories against this pattern and alert on matches.
Alert triage workflow
Set up a webhook or GitHub Actions workflow that forwards new secret scanning alerts to your security team's Slack channel or ticket queue. The triage workflow: (1) Rotate the secret immediately. (2) Check if the secret was used (provider access logs). (3) Remove from history. (4) Close the alert as remediated. Target a 4-hour SLA for high-confidence alerts (verified by provider).
Remediation: Secrets Already in History
When secrets are found in existing git history, deletion from the working tree is not sufficient. You must rewrite history and notify all collaborators.
Subscribe to unlock Remediation & Mitigation steps
Free subscribers unlock full IOC lists, Sigma detection rules, remediation steps, and every daily briefing.
Preventing Secrets at the Source
Scanning catches secrets after they are written. These practices reduce how often secrets end up in code in the first place.
Mandate a secrets manager, never hardcode
AWS Secrets Manager, HashiCorp Vault, GCP Secret Manager, Azure Key Vault. Applications should retrieve secrets at runtime via SDK calls, never from environment variable files checked into git or hardcoded in source. Add a linting rule to your CI that fails on detected hardcoded patterns (this is what gitleaks does, but make it a documented policy with onboarding coverage).
Use .env file templates, never actual .env files
Keep .env.example in version control with placeholder values. Add .env, .env.local, .env.production to .gitignore globally (git config --global core.excludesfile ~/.gitignore_global). Many developers check in .env files after overwriting them with real values, the .gitignore is the last line of defense before the pre-commit hook.
Short-lived credentials over long-lived secrets
OIDC-based authentication in GitHub Actions eliminates static AWS access keys entirely, the action gets a short-lived token that expires after the job. AWS IAM Roles Anywhere and GCP Workload Identity Federation do the same for other contexts. Short-lived credentials that expire in minutes have minimal value even if exposed.
The bottom line
Deploy gitleaks as a pre-commit hook and as a required CI check this week. Enable GitHub Advanced Security push protection for your organization today, it is the only control that blocks a secret commit at the server before it can be exploited. Then run a one-time gitleaks scan across all repositories to find what is already there. Rotate anything found. Rewrite the history. The combination of pre-commit, CI blocking, and GHAS push protection makes accidental secret exposure an exception rather than a routine occurrence.
Frequently asked questions
Does deleting a file with a secret from git history actually remove it?
No. git rm or a new commit that removes the file does not delete the secret from git history, the old commit containing the secret still exists and is reachable via the commit hash. Anyone who cloned the repository before the deletion already has the secret in their local history. Proper removal requires rewriting history with git-filter-repo and notifying all collaborators to re-clone. The only reliable fix is to assume the secret is compromised and rotate it.
Should I use gitleaks or TruffleHog?
Both are widely used and complementary. Gitleaks is faster, simpler to configure, and works well as a pre-commit hook and in CI pipelines where speed matters. TruffleHog is more thorough, uses entropy-based detection in addition to pattern matching, supports more secret types, and has a --verified flag that checks if found secrets are still valid. Use gitleaks at the pre-commit stage and TruffleHog in CI/CD for a deeper scan.
What do I do if GitHub Advanced Security finds a secret and sends me an alert?
Treat it as a breach: (1) Rotate the secret immediately, do not wait. Automated scanners can find and attempt to use exposed secrets within minutes of a push. (2) After rotation, use git-filter-repo to remove the secret from git history and force-push. (3) Check your provider's access logs for the period the secret was exposed to determine if it was used. (4) If the secret was a cloud provider key, check CloudTrail, GCP Audit Logs, or Azure Activity logs for unexpected API calls.
How do I prevent developers from bypassing pre-commit hooks with --no-verify?
Pre-commit hooks are purely local and can always be bypassed with git commit --no-verify. The reliable enforcement layer is CI/CD, a gitleaks scan in your CI pipeline that blocks merging a PR if secrets are detected cannot be bypassed by individual developers. Pre-commit hooks are a fast feedback mechanism, not a security boundary. The security boundary is the CI scan.
How do I handle a secret that was already committed to a public GitHub repository?
Treat the secret as fully compromised the moment it is pushed to a public repository -- bots scan GitHub for secrets in real time and may have already harvested it. Immediate steps: (1) Revoke the exposed credential immediately in the service that issued it (AWS IAM, GitHub, Stripe, etc.) -- this is the priority before any git cleanup. (2) Check the service's audit log for unauthorized use of the exposed credential from the time of the commit to the time of revocation. (3) Remove the secret from git history using git filter-repo (the recommended replacement for BFG Repo Cleaner): git filter-repo --path secret-file.txt --invert-paths. (4) Force-push the cleaned history. (5) Contact GitHub support to clear cached views. History rewriting does not undo exposure -- revocation is the critical step.
How do I handle secrets scanning false positives in a monorepo with hundreds of microservices?
In large monorepos, false positive rates can be high enough to cause teams to disable scanning or ignore alerts entirely. Use a tiered allowlisting strategy: first, identify false positive patterns that are truly structural (test fixture values, documentation examples, placeholder strings) and add them to a repository-level .gitleaks.toml allowlist with regex patterns scoped as narrowly as possible. Second, use the allowlist path field to restrict exceptions to specific directories -- a placeholder credential pattern in docs/ should only be excepted for files under docs/, not the entire repo. Third, for secrets that teams argue are not real secrets (e.g., GCP service account JSON for a non-production sandbox project), require a documented exception with expiry in your security tracker rather than a permanent allowlist entry -- this forces periodic review. Treat any allowlist entry that cannot be justified as a real-secret risk until proven otherwise.
Sources & references
Free resources
Critical CVE Reference Card 2025–2026
25 actively exploited vulnerabilities with CVSS scores, exploit status, and patch availability. Print it, pin it, share it with your SOC team.
Ransomware Incident Response Playbook
Step-by-step 24-hour IR checklist covering detection, containment, eradication, and recovery. Built for SOC teams, IR leads, and CISOs.
Get threat intel before your inbox does.
50,000+ security professionals read Decryption Digest for early warnings on zero-days, ransomware, and nation-state campaigns. Free, daily, no spam.
Unsubscribe anytime. We never sell your data.

Founder & Cybersecurity Evangelist, Decryption Digest
Cybersecurity professional with expertise in threat intelligence, vulnerability research, and enterprise security. Covers zero-days, ransomware, and nation-state operations for 50,000+ security professionals every morning.
Win a $2,495 Black Hat pass.
Full-access to Black Hat USA 2026 in Las Vegas. Subscribe free to enter.
