
September 12, 2026
12 min read
By Kokil Thapa | Last reviewed: September 2026
A committed .env file or hard-coded Stripe key can sit in Git for years. You need to detect leaked secrets with Gitleaks and TruffleHog before a crawler or attacker does. On production Laravel apps and API integrations I maintain, a single leaked token can mean payment abuse, SMS spam, or full database access. These two scanners catch credentials in working trees, pull requests, and entire commit histories—locally and in CI.
Why should you detect leaked secrets with Gitleaks and TruffleHog before attackers do?
Git never forgets. A secret removed in the latest commit still lives in older blobs. Bots scan public GitHub hourly. Private repos leak through forks, misconfigured CI logs, and former contractors.
I have seen this on real client projects. A Khalti or eSewa test key pushed during a late-night deploy sat in history for months. Nobody noticed until a support ticket flagged odd transactions. Prevention is cheaper than incident response.
Secret scanners sit early in your delivery pipeline. They complement—not replace—proper secrets management with HashiCorp Vault, Ansible Vault, and environment variables on the server. Think of Gitleaks and TruffleHog as smoke detectors. Vault is the fireproof safe.
Common leak sources on PHP and Laravel stacks include:
.envfiles committed by mistake during onboarding- Debug dumps left in Blade templates or PHPUnit fixtures
- Postman collections exported into the repo
- Deploy scripts with inline database passwords
- CI variables printed when
set -xis enabled in bash
Payment integrations make this urgent. A leaked Stripe secret on an eCommerce site can drain funds in minutes. Legal-tech portals with document storage face GDPR-style exposure if cloud storage keys leak. Treat scanning as part of testing and optimization, not an optional security extra.
What is the difference between Gitleaks and TruffleHog for secret scanning?
Both tools scan Git repositories. They differ in speed, verification depth, and operational fit. Many teams run Gitleaks on every push and TruffleHog on scheduled full-history jobs.
| Criteria | Gitleaks | TruffleHog |
|---|---|---|
| Detection method | Regex rules + entropy heuristics | Regex + optional live API verification |
| Speed on large repos | Very fast; Go binary | Slower when verification enabled |
| False positives | Moderate; tune allowlists | Lower with --only-verified |
| Git history depth | Full history, shallow clones OK | Full history; supports many VCS hosts |
| CI integration | Native exit codes, SARIF output | GitHub Action, GitLab template |
| Custom rules | TOML config, inline allowlists | Detector plugins, custom regex |
| Best use case | Fast PR gate, pre-commit hook | Deep audit, verified credential hunt |
Gitleaks excels as a lightweight gate. It ships hundreds of built-in rules for AWS, GitHub, Slack, Stripe, and generic high-entropy strings. TruffleHog goes further by calling provider APIs to confirm whether a key still works. That verification step cuts noise but needs outbound network access in CI.
On sister sites I deploy with GitLab CI and Deployer 7, Gitleaks runs in under thirty seconds on typical Laravel repos. TruffleHog with verification on the same repo may take several minutes. Schedule it nightly rather than on every commit.
For deeper background on CI wiring, see the companion guide on secrets scanning in Git and CI with Gitleaks. For pipeline secret storage patterns, read manage secrets safely in pipelines and CI/CD secrets management best practices.
How do you install and run Gitleaks on your repository?
Gitleaks ships as a single Go binary. Install it on Ubuntu 22/24 dev machines and CI runners the same way.
Install Gitleaks on Linux
# Download latest release (check github.com/gitleaks/gitleaks/releases)
curl -sSL https://github.com/gitleaks/gitleaks/releases/latest/download/gitleaks_linux_x64.tar.gz \
| tar -xz -C /usr/local/bin gitleaks
gitleaks version
On macOS, use Homebrew: brew install gitleaks. Pin the version in CI so rule behaviour stays predictable across pipeline runs.
Scan the working directory
cd /var/www/my-laravel-app
# Scan unstaged + staged changes
gitleaks protect --staged --verbose
# Scan entire repo including full Git history
gitleaks detect --source . --verbose
The protect subcommand suits pre-commit hooks. The detect subcommand walks every commit. Exit code 1 means findings exist—wire that into CI to fail the build.
Custom Gitleaks config
Create .gitleaks.toml at the repo root. Allowlist test fixtures and dummy keys used in PHPUnit:
title = "Project Gitleaks config"
[allowlist]
description = "Ignore test fixtures and example env"
paths = [
'''tests/fixtures/''',
'''\.env\.example''',
]
commits = [
"abc123deadbeef",
]
[[rules]]
id = "custom-stripe-test-key"
description = "Stripe test publishable key pattern"
regex = '''pk_test_[a-zA-Z0-9]{24,}'''
Run with explicit config:
gitleaks detect --source . --config .gitleaks.toml --report-format sarif \
--report-path gitleaks-report.sarif
SARIF output integrates with GitHub Advanced Security and GitLab SAST dashboards. Store reports as CI artefacts for audit trails on client portals like Mijar Law Associates where document security matters.
Pre-commit hook with Gitleaks
Add a hook so developers catch leaks before push:
#!/bin/sh
# .git/hooks/pre-commit
gitleaks protect --staged --redact --verbose
if [ $? -eq 1 ]; then
echo "Gitleaks found secrets. Commit blocked."
exit 1
fi
Make it executable: chmod +x .git/hooks/pre-commit. For team-wide enforcement, use the official Gitleaks repository pre-commit template or a shared hook manager.
How do you scan Git history with TruffleHog in CI/CD?
TruffleHog installs similarly and adds verified detection against live services. Use it when you need confidence that a found key is not just high-entropy noise.
Install TruffleHog
# Binary install on Linux amd64
curl -sSfL https://raw.githubusercontent.com/trufflesecurity/trufflehog/main/scripts/install.sh \
| sh -s -- -b /usr/local/bin
trufflehog --version
Official docs live at the TruffleHog GitHub project. Review release notes before upgrading in production CI.
Scan a local Git repo
cd /var/www/my-laravel-app
# Full Git history scan
trufflehog git file://. --json
# Only report verified active secrets
trufflehog git file://. --only-verified --fail
The --only-verified flag is essential for nightly jobs on large monorepos. It skips placeholder strings that match patterns but fail provider validation.
GitLab CI example
Many projects I maintain use GitLab CI. A practical two-stage approach:
stages:
- test
- security
gitleaks:
stage: security
image:
name: ghcr.io/gitleaks/gitleaks:latest
entrypoint: [""]
script:
- gitleaks detect --source . --config .gitleaks.toml --verbose
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
trufflehog-nightly:
stage: security
image: alpine:latest
before_script:
- apk add --no-cache curl git
- curl -sSfL https://raw.githubusercontent.com/trufflesecurity/trufflehog/main/scripts/install.sh | sh -s -- -b /usr/local/bin
script:
- trufflehog git file://. --only-verified --fail --json > trufflehog-report.json
artifacts:
paths:
- trufflehog-report.json
expire_in: 30 days
rules:
- if: $CI_PIPELINE_SOURCE == "schedule"
Run Gitleaks on every merge request. Schedule TruffleHog nightly to control runner cost. Never echo secret values in job logs—both tools support redaction flags.
GitHub Actions snippet
- name: Gitleaks scan
uses: gitleaks/gitleaks-action@v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: TruffleHog verified scan
uses: trufflesecurity/trufflehog@main
with:
path: ./
base: ${{ github.event.repository.default_branch }}
head: HEAD
extra_args: --only-verified
Pair scanning with encrypted secrets in repo using SOPS and age for config files that must live in Git. Scanning catches mistakes; encryption handles intentional committed config.
- Install both scanners on developer machines and CI runners.
- Add
.gitleaks.tomlallowlists for legitimate test data. - Fail merge requests when Gitleaks exits non-zero.
- Schedule TruffleHog with
--only-verifiedfor deep audits. - Rotate and purge any finding before closing the ticket.
For Laravel 13 projects on PHP 8.3+, keep secrets in .env on the server only. Use Linux system administration practices: restrict .env to the deploy user, never commit it, and reload PHP-FPM after deploy so opcache picks up config changes without exposing values in logs.
What should you do when a scanner finds a leaked secret in production?
Finding a secret is not the finish line. Rotation and history cleanup matter more than the scan itself. Treat every verified finding as an active incident until proven otherwise.
Immediate response checklist
- Revoke the credential at the provider dashboard first—Stripe, AWS IAM, SendGrid, Khalti, or whichever service issued it.
- Issue a new key and update production
.envthrough your normal deploy path. - Check access logs for abuse during the exposure window.
- Notify stakeholders if PII or payment data could be affected.
Deleting the file in a new commit is not enough. The secret remains in Git objects. Use git filter-repo or BFG Repo-Cleaner to rewrite history, then force-push only after team coordination. Everyone must re-clone afterward.
# Example: remove .env from entire history with git-filter-repo
pip install git-filter-repo
git filter-repo --path .env --invert-paths
# Force push (coordinate with team first)
git push origin --force --all
On shared hosting without Git access for attackers, history rewrite still matters if the repo was ever public or forked. For web development clients on budget shared plans, prevention beats rewrite—many never enable force-push rights.
Reduce repeat leaks
Move secrets out of code entirely. Use environment variables on Ubuntu servers, GitLab CI masked variables, or a vault product. Add .env to .gitignore on day one. Ship .env.example with placeholder values only.
Test your allowlists with the regex tester before adding custom Gitleaks rules. Generate strong replacement keys with the password generator—never reuse rotated secrets.
Train the team. A five-minute onboarding doc beats a post-incident scramble. Link new developers to handling secrets in CI/CD pipelines safely and protecting PII and secrets in LLM apps if they touch AI integrations.
For eCommerce stacks handling Stripe or PayPal, review payment-integrated Laravel projects as a reminder that gateway keys belong in server env, never in frontend JavaScript bundles. Decode suspicious strings during triage with the Base64 encoder and decoder—some leaks hide encoded credentials in config files.
Key Takeaways
- Run Gitleaks on every pull request for fast regex-based detection across staged files and full Git history.
- Schedule TruffleHog with
--only-verifiedfor nightly deep scans that confirm active credentials against provider APIs. - Rotate every exposed secret immediately—deleting the file in a new commit does not remove it from Git objects.
- Maintain a
.gitleaks.tomlallowlist for test fixtures, but never allowlist production key patterns. - Wire scanner exit codes into CI so merges and deploys halt on findings, not just warn.
- Combine scanning with proper secrets storage—env vars, Vault, or SOPS—not as a substitute for them.
People Also Ask
Can Gitleaks scan only new commits instead of full history?
Yes. Use gitleaks protect --staged for pre-commit checks and configure CI to diff against the target branch. For merge requests, pass --log-opts with a range like origin/main..HEAD to limit scope. Full-history detect runs belong on schedules or after onboarding a legacy repo.
Does TruffleHog work on private GitLab repositories?
TruffleHog scans local clones, so any repo your CI runner can clone works—including private GitLab projects. For GitLab-hosted scanning without a local clone, use TruffleHog's GitLab integration modes documented in their repository. Ensure runners have outbound HTTPS for verified checks.
Will secret scanning slow down my CI pipeline?
Gitleaks adds seconds to most Laravel-sized repos. TruffleHog with verification can add minutes on large histories. Split the workload: Gitleaks on every MR, TruffleHog on a nightly schedule. Cache nothing that contains scan output with unredacted findings.
Are .env.example files flagged as leaks?
They can be if they contain realistic-looking keys instead of placeholders. Use obvious dummy values like sk_test_REPLACE_ME. Add .env.example to your Gitleaks allowlist only when values are clearly fake. Never put real credentials in example files "for convenience."
Ship code without shipping credentials
You can detect leaked secrets with Gitleaks and TruffleHog today with two binaries and a CI job. Start with Gitleaks on merge requests, add TruffleHog verification on a nightly cron, and document your rotation runbook before the first alert fires. On production systems I maintain—from legal portals to eCommerce builds—scanning is standard ops, not optional security theatre.
Need help auditing an existing Laravel or WordPress repo, wiring GitLab CI gates, or cleaning history after a leak? Contact us for a focused security review. Browse the portfolio for examples of production apps shipped with proper env-based config, or read more on the blog about ongoing support and maintenance for live systems.
Frequently Asked Questions
0 Comments
Leave a comment
Your email is not published. Comments appear once they have been read. Sign in to have your details filled in.

