linuxlab.io
Tutorials▾
  • Linux & networking
    File system, processes, TCP/IP, BGP and OSPF
    →
  • Terraform & IaC
    HCL, state, plan/apply on a LocalStack sandbox
    →
  • Git & GitHub
    Object model, plumbing, branching, GitHub Actions
    →
All tutorials →
PricingAboutSign inCreate account
/
Intro
Lessons
Footer
linuxlab-TutorialsPricingAboutPrivacy & cookies
Copyright © 2026 LinuxLab. All rights reserved.
linuxlab.io
Tutorials▾
  • Linux & networking
    File system, processes, TCP/IP, BGP and OSPF
    →
  • Terraform & IaC
    HCL, state, plan/apply on a LocalStack sandbox
    →
  • Git & GitHub
    Object model, plumbing, branching, GitHub Actions
    →
All tutorials →
PricingAboutSign inCreate account
/
  • Introduction
  • Chapters
  • How it works
  • Lessons
  • Knowledge base
  • Interview prep
home/git/kb/Security/secret-scanning

kb/security ── Security ── intermediate

Secret Scanning in a Repository

Scan your repo regularly for accidentally committed secrets (API keys, passwords, tokens). The main tools: gitleaks, detect-secrets, trufflehog. The best time to catch them is before the commit, with a pre-commit hook. After an exposure, key rotation is non-negotiable. History cleanup is optional.

view as markdownaka: detect-secrets, gitleaks, leaked-credentials

The most common security mistake in Git is committing an API key, a database password, or AWS credentials. It counts as an exposure the moment it enters the repo. Even if you delete it in a later commit, the file sits in history, reachable via git show <sha>:path, and anyone with repo access can read it.

In a public repo, a secret is compromised within minutes. Bots scan GitHub continuously and automatically try any keys they find. On AWS or a similar cloud provider, a leaked key can rack up significant charges (the typical scenario: launching heavy EC2 or GPU instances for mining) before you notice anything.

Defense in three layers

1. Keep secrets out of the repo entirely

  • Put .env files in .gitignore (gitignore).
  • Pull secrets from environment variables, not from files.
  • Use placeholders in code; load real values from a vault, AWS Secrets Manager, Doppler, or 1Password.

2. Pre-commit hook with a scanner

The most popular tools:

  • gitleaks: a Go binary, fast. Configured via .gitleaks.toml.
  • detect-secrets (Yelp): Python, finer-grained control through a "baseline" file.
  • trufflehog: Go, also checks entropy (catches strings that look like tokens even without a known pattern).

Via the pre-commit framework (gpg-signing):

yaml
# .pre-commit-config.yaml
repos:
  - repo: https://github.com/gitleaks/gitleaks
    rev: v8.21.0
    hooks:
      - id: gitleaks

A commit containing a suspicious string is now blocked:

gitleaks failed: aws-access-key found in src/config.py:15

3. Server-side scanning

  • GitHub Secret Scanning is built in for public repos at no cost, and available for private repos through GHAS (paid). It scans on push. When a key is found, it automatically notifies the provider (AWS, Stripe, etc.), which can then revoke the key.
  • GitLab Secret Detection is the equivalent in its SAST suite.
  • A custom pre-receive hook on a bare server that rejects pushes containing suspicious strings.

The server layer is the final safety net. Even if a developer bypasses the pre-commit hook with --no-verify, the server scanner catches it.

What to do after an exposure

In order:

1. Rotate the key. Now.

Not "fix the history and then rotate." Rotation first:

  • AWS: create a new access key, delete the old one.
  • Stripe: revoke the API key in the dashboard.
  • GitHub PAT: revoke in Settings.
  • Any provider: within thirty minutes.

This is the only action that eliminates the risk. History cleanup is hygiene, not security.

2. Notify the team

Someone may have cloned the repo before the fix. Let them know the secret has been rotated so they do not try to use the old value.

3. (Optional) Clean the history

If the repo is private and the secret has not reached an attacker, you can reduce the exposure window with git-filter-repo:

bash
git filter-repo --replace-text replace.txt
# where replace.txt contains:
# AKIA********** ==> [REMOVED]

This rewrites all history. After that, git push --force (requires permissions and temporary disabling of branch protection). All clones become stale; everyone must clone again.

Do not clean without rotating. That creates a false sense of security. Rotation is required. Cleanup is optional.

What leaks most often

  • AWS access keys (AKIA*): the most common and most dangerous.
  • GitHub PAT/Personal Access Tokens (ghp_*).
  • Stripe/Twilio/SendGrid API keys.
  • Database passwords in database.yml, application.properties.
  • OAuth client_secret in .env files.
  • SSH keys copied to .ssh/ (see ssh-keys-git).
  • Certificates and private keys in .pem, .key, .crt.

Scanners know most of these patterns out of the box. gitleaks ships with rules covering hundreds of providers.

Pitfalls

  • False positives. A scanner may flag a random hash as a leaked key. For detect-secrets, --baseline remembers "these are known; do not alert."
  • Old secrets in history. When you first enable the scanner on CI, it may alert on old history. The strategy: clean the old ones separately (or accept them as baseline), then turn the scanner on for new commits only.
  • .env.example is also scanned. If it contains real values instead of placeholders, the scanner will catch them. Keep placeholders there (<your-key-here>).

§ команды

bash
gitleaks detect --source .

Scan the repo manually

bash
git log -p -S 'AKIA'

Search for a string across all history (pickaxe)

bash
git filter-repo --replace-text replace.txt

Replace a string across all history (after rotating the key)

§ см. также

  • gitignore.gitignoreA file in the repo root listing ignore patterns: what Git should skip entirely. Do not confuse it with staging. It has no effect on already-tracked files. It is your primary defense against accidentally committing secrets and junk.
  • git-filter-repogit filter-repo: Rewriting HistoryThe modern replacement for the deprecated `git filter-branch`. Rewrites history in place: removes files, changes author emails, replaces strings. Use it to remove secrets or large binaries that landed in the repo.
  • gpg-signingGPG Commit SigningGit commits can be signed with a GPG key (or an SSH key starting with Git 2.34). A signature cryptographically proves that the signer had access to the private key at the time of the commit. The link between "key" and "specific person" comes from key verification (web of trust in OpenPGP, confirmation through a GitHub account, etc.), not from Git itself. Git does not verify who you are.
Footer
linuxlab-
Copyright © 2026 LinuxLab. All rights reserved.
Tutorials
Pricing
About
Privacy & cookies