DEV Community

zakaria zermani
zakaria zermani

Posted on

Stop Committing Secrets: A Practical Betterleaks + Git Hooks Setup for Every Development Team

Security incidents often start with a simple mistake.

A developer accidentally commits an API key, a database password, a private key, or a cloud credential. The secret gets pushed to a repository, appears in CI logs, gets replicated to forks, or becomes part of Git history.

Even when detected quickly, the cleanup can be painful:

  • Rotate credentials
  • Clean repository history
  • Investigate exposure
  • Update environments
  • Document the incident

A much better approach is to prevent secrets from being committed in the first place.

In this article, we'll configure Betterleaks and Git pre-commit hooks to automatically scan staged changes and block commits containing sensitive information.


Why Local Secret Scanning Matters

Many organizations rely on:

  • GitHub Secret Scanning
  • GitLab Secret Detection
  • CI/CD security pipelines
  • Repository scanning solutions

While these tools are important, they usually identify problems after the secret has already entered the repository.

Local scanning shifts detection further left.

Benefits

✅ Immediate feedback for developers

✅ Secrets never reach Git history

✅ Faster remediation

✅ Consistent security practices

✅ Reduced risk of accidental exposure

The earlier a problem is discovered, the cheaper it is to fix.


Step 1: Install Betterleaks

Install Betterleaks on your workstation.

macOS

brew install betterleaks
Enter fullscreen mode Exit fullscreen mode

Linux

BETTERLEAKS_VERSION="1.8.1"

curl -sSfL \
"https://github.com/betterleaks/betterleaks/releases/download/v${BETTERLEAKS_VERSION}/betterleaks_${BETTERLEAKS_VERSION}_linux_x64.tar.gz" \
| tar -xz

sudo mv betterleaks /usr/local/bin/
Enter fullscreen mode Exit fullscreen mode

Verify Installation

betterleaks --version
Enter fullscreen mode Exit fullscreen mode

If a version number is displayed, you're ready to continue.


Step 2: Store Git Hooks Inside the Repository

By default, Git stores hooks inside:

.git/hooks
Enter fullscreen mode Exit fullscreen mode

The problem is that this directory is not version-controlled.

To ensure every developer uses the same hooks, create a dedicated directory:

my-project/
├── .githooks/
│   └── pre-commit
├── .betterleaks.toml
└── README.md
Enter fullscreen mode Exit fullscreen mode

Configure Git to use this directory:

git config core.hooksPath .githooks
Enter fullscreen mode Exit fullscreen mode

This command only needs to be executed once per cloned repository.


Step 3: Create the Pre-Commit Hook

Create the file:

.githooks/pre-commit
Enter fullscreen mode Exit fullscreen mode

Add the following content:

#!/usr/bin/env bash

# Verify Betterleaks is installed
if ! command -v betterleaks &> /dev/null; then
    echo "Betterleaks is not installed."
    echo "Please install Betterleaks before committing."
    exit 1
fi

echo "Running Betterleaks scan..."

betterleaks git . \
    --staged \
    --config .betterleaks.toml

EXIT_CODE=$?

if [ $EXIT_CODE -ne 0 ]; then
    echo ""
    echo "Secrets detected."
    echo "Commit blocked."
    exit 1
fi

echo "No secrets found."
exit 0
Enter fullscreen mode Exit fullscreen mode

Make the hook executable:

chmod +x .githooks/pre-commit
Enter fullscreen mode Exit fullscreen mode

Now every commit will automatically trigger a secret scan.


Step 4: Configure Betterleaks

Create the configuration file:

.betterleaks.toml
Enter fullscreen mode Exit fullscreen mode

Example configuration:

title = "Project-Wide Betterleaks Configuration"

[extend]
useDefault = true

# Optional:
# disabledRules = ["generic-api-key"]

[[rules]]
id = "custom-api-token"

description = "Detect custom API tokens"

regex = '''MYTOKEN_[A-Za-z0-9]{32}'''

keywords = [
  "MYTOKEN_"
]

[allowlist]

description = "Ignore test fixtures"

paths = [
  '''(^|/)testdata/''',
  '''(^|/)fixtures/''',
  '''(^|/)__mocks__/'''
]

stopwords = [
  "dummy_token",
  "example_secret",
  "test_api_key"
]
Enter fullscreen mode Exit fullscreen mode

This configuration:

  • Uses Betterleaks' built-in detection rules
  • Adds project-specific secret detection
  • Reduces false positives
  • Excludes known test data

Step 5: Test the Setup

Let's verify that the hook works.

Create a file containing a fake GitHub token:

echo "token: ghp_AbC123xYz456D7Ef89GhI01JkLmNoPqRsTuV" > test-secret.txt
Enter fullscreen mode Exit fullscreen mode

Stage the file:

git add test-secret.txt
Enter fullscreen mode Exit fullscreen mode

Attempt a commit:

git commit -m "testing secret detection"
Enter fullscreen mode Exit fullscreen mode

Expected output:

Running Betterleaks scan...

Secrets detected.
Commit blocked.
Enter fullscreen mode Exit fullscreen mode

The commit will fail, preventing the secret from entering the repository.


Handling False Positives

No detection tool is perfect.

If Betterleaks incorrectly identifies a value as a secret, you have several options.

Allow a Specific Line

example_value # betterleaks:allow
Enter fullscreen mode Exit fullscreen mode

Ignore Files or Directories

Create a:

.betterleaksignore
Enter fullscreen mode Exit fullscreen mode

file to define exclusions.

Customize Detection Rules

Adjust your rules inside:

.betterleaks.toml
Enter fullscreen mode Exit fullscreen mode

The goal is to reduce noise while maintaining effective security controls.


Emergency Bypass

In rare situations, you may need to bypass the hook:

git commit --no-verify -m "emergency commit"
Enter fullscreen mode Exit fullscreen mode

Use this carefully.

If developers regularly bypass security controls, it may indicate that the rules need refinement.


Onboarding New Developers

A simple developer onboarding process might look like:

git clone <repository>

cd <repository>

brew install betterleaks

git config core.hooksPath .githooks
Enter fullscreen mode Exit fullscreen mode

That's it.

From that point onward, every commit is automatically checked before it is created.


Defense in Depth: Local + CI/CD Scanning

Local secret scanning should complement, not replace, existing security controls.

A layered approach typically includes:

Layer Purpose
Pre-Commit Hooks Immediate developer feedback
Pull Request Validation Team-level review
CI/CD Scanning Automated enforcement
Repository Scanning Continuous monitoring
Secret Management Solutions Secure storage and rotation

Security controls are most effective when they work together.


Conclusion

Secret leaks are among the easiest security incidents to prevent.

By integrating Betterleaks directly into the local development workflow, teams can catch sensitive information before it enters a repository.

The setup is lightweight, easy to maintain, and provides immediate value without disrupting developers.

If you're already scanning repositories and CI/CD pipelines for secrets, consider adding local detection as another layer of defense.

The best secret leak is the one that never reaches Git in the first place.


Have You Tried Local Secret Scanning?

How does your team prevent accidental secret exposure?

Do you rely on GitHub Secret Scanning, GitLab Secret Detection, gitleaks, Betterleaks, custom tooling, or a combination of approaches?

I'd be interested to hear what has worked best in your environment.

Top comments (0)