Kokil Thapa - Professional Web Developer in Nepal
Freelancer Web Developer in Nepal with 15+ Years of Experience

Kokil Thapa is an experienced full-stack web developer focused on building fast, secure, and scalable web applications. He helps businesses and individuals create SEO-friendly, user-focused digital platforms designed for long-term growth.

Detect Leaked Secrets with Gitleaks and TruffleHog

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.

Secret Scanning in the Dev PipelineLocal Devpre-commit hookPull RequestCI gateFull Historynightly scanProductionruntime env varsWhat Gets ScannedAPI keys · OAuth tokens · DB URLs · .env filesPrivate keys · AWS credentials · webhook secretsPayment gateway keys · SMTP passwordsGitleaks regex + TruffleHog verification
Detect leaked secrets with Gitleaks and TruffleHog at every stage from local commits to production deployment.

Common leak sources on PHP and Laravel stacks include:

  • .env files 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 -x is 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.

CriteriaGitleaksTruffleHog
Detection methodRegex rules + entropy heuristicsRegex + optional live API verification
Speed on large reposVery fast; Go binarySlower when verification enabled
False positivesModerate; tune allowlistsLower with --only-verified
Git history depthFull history, shallow clones OKFull history; supports many VCS hosts
CI integrationNative exit codes, SARIF outputGitHub Action, GitLab template
Custom rulesTOML config, inline allowlistsDetector plugins, custom regex
Best use caseFast PR gate, pre-commit hookDeep 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.

Gitleaks vs TruffleHog Decision FlowNeed a scan?Fast PR gateUse GitleaksFull auditBoth toolsVerify liveTruffleHogFinding any secret?Rotate immediately · Purge from Git historyNever rely on delete alone
Choose Gitleaks for speed on pull requests and TruffleHog when you need verified credential detection across Git history.

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.

Gitleaks Git History ScanCommit 1Commit 2Commit 3.env leakedCommit 4HEADgitleaks detect --source .Walks every blob in historyFinding at Commit 3 even if file deleted laterReport: file, line, rule ID, commit SHAExit code 1 blocks CI merge
Gitleaks scans every Git commit blob, so deleted secrets in old commits still trigger alerts during detect leaked secrets workflows.

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.

  1. Install both scanners on developer machines and CI runners.
  2. Add .gitleaks.toml allowlists for legitimate test data.
  3. Fail merge requests when Gitleaks exits non-zero.
  4. Schedule TruffleHog with --only-verified for deep audits.
  5. 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.

TruffleHog Verified DetectionGit Repohistory blobsTruffleHogregex matchProvider APIlive verifyVerifiedactive secretSkippedfalse positiveCI fails with --fail flagBlock deploy until secret rotated and history cleaned
TruffleHog verifies suspected secrets against provider APIs, reducing false positives when you detect leaked secrets with Gitleaks and TruffleHog together.

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 .env through 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-verified for 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.toml allowlist 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

Both tools scan Git repositories but differ in speed, verification depth, and operational fit. Gitleaks uses regex rules plus entropy heuristics—it is very fast on large repos, with moderate false positives you tune through TOML allowlists. TruffleHog adds optional live API verification against provider services, producing fewer false positives with --only-verified but running slower when verification is enabled. Many teams run Gitleaks on every push as a lightweight merge-request gate and schedule TruffleHog nightly for deep verified credential hunts across full Git history.

Git never forgets. A secret removed in the latest commit still lives in older blobs, and bots scan public GitHub hourly. Private repos leak through forks, misconfigured CI logs, and former contractors. On production Laravel apps and API integrations I maintain, a single leaked token can mean payment abuse, SMS spam, or full database access. I've seen Khalti or eSewa test keys pushed during a late-night deploy sit in history for months until odd transactions raised alarms. Prevention is cheaper than incident response.

Gitleaks ships as a single Go binary. On Ubuntu 22/24 dev machines and CI runners, download the latest release from GitHub, extract it to /usr/local/bin, and confirm with gitleaks version. On macOS use Homebrew. Pin the version in CI so rule behaviour stays predictable across pipeline runs. Run gitleaks protect --staged --verbose for unstaged and staged changes before commit. Run gitleaks detect --source . --verbose to walk every commit in full Git history. Exit code 1 means findings exist—wire that into CI to fail the build.

protect scans staged and unstaged working-tree changes for pre-commit hooks; detect walks every commit across full Git history.

Create .gitleaks.toml at the repo root. Use the allowlist section to ignore test fixture paths, .env.example, and specific commits when needed. Add custom rules with id, description, and regex for project-specific patterns such as Stripe test publishable keys. Run with 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. Test allowlist regex before adding custom rules, and never allowlist production key patterns—only legitimate dummy test data.

Add a shell script to .git/hooks/pre-commit that runs gitleaks protect --staged --redact --verbose and exits 1 if findings exist, blocking the commit with a clear error message. Make it executable with chmod +x. For team-wide enforcement beyond individual machines, use the official Gitleaks repository pre-commit template or a shared hook manager. This catches leaks before push and complements CI gates. On real client projects, local hooks save merge request cycles and prevent accidental .env commits during developer onboarding.

Install TruffleHog via the official install script on Linux amd64, placing the binary in /usr/local/bin, then confirm with trufflehog --version. Review release notes before upgrading in production CI. Scan a local clone with trufflehog git file://. --json for full history output. Add --only-verified --fail to report only active credentials and exit non-zero on findings. The --only-verified flag skips placeholder strings that match patterns but fail provider validation. TruffleHog needs outbound HTTPS in CI because verified checks call live provider APIs.

Use a two-stage security pipeline. Run Gitleaks on every merge request with the official container image and your .gitleaks.toml config. Schedule TruffleHog nightly with rules tied to CI_PIPELINE_SOURCE schedule—install git and the binary in an Alpine job, then run trufflehog git file://. --only-verified --fail --json and store the report as a 30-day artifact. Never echo secret values in job logs; both tools support redaction flags. This split keeps merge request feedback fast while running deep verified audits without blocking every push.

No. The secret remains in Git objects. Use git filter-repo or BFG Repo-Cleaner to rewrite history, then coordinate a force-push and have the team re-clone.

Gitleaks adds seconds to most Laravel-sized repos—in practice under thirty seconds on typical projects. TruffleHog with verification can add several minutes on large histories. Split the workload: run Gitleaks on every merge request and schedule TruffleHog nightly to control runner cost. Cache nothing that contains scan output with unredacted findings. For merge requests, limit Gitleaks scope with --log-opts ranges like origin/main..HEAD instead of full history on every push. Full-history detect runs belong on schedules or when onboarding a legacy repository.

Treat every verified finding as an active incident until proven otherwise. 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 .env through 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 until you rewrite history with git filter-repo after team coordination, then force-push and have everyone re-clone.

Yes. Use gitleaks protect --staged for pre-commit checks on unstaged and staged changes. In CI, configure merge request jobs to diff against the target branch by passing --log-opts with a range like origin/main..HEAD to limit scope to new commits only. Full-history runs with gitleaks detect --source . belong on schedules or when first onboarding a legacy repository where years of accidental commits may exist. This keeps pull request gates fast while still allowing periodic deep scans across every Git blob, including secrets deleted in earlier commits.

TruffleHog scans local clones, so any repository your CI runner can clone works—including private GitLab projects. Ensure runners have outbound HTTPS access for verified checks that call provider APIs. For GitLab-hosted scanning without a local clone, TruffleHog offers GitLab integration modes documented in their repository. The practical pattern on projects I maintain is a scheduled pipeline job that clones the repo and runs trufflehog git file://. --only-verified --fail. Private visibility does not protect you if the repo was forked, CI logs exposed values, or a contractor cloned it locally.

They can be if values look realistic instead of placeholders. Use obvious dummy values like sk_test_REPLACE_ME and allowlist only clearly fake entries.

Typical sources include .env files 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, and CI variables printed when set -x is enabled in bash. Payment integrations make this urgent—a leaked Stripe secret on an eCommerce site can drain funds in minutes. For Laravel 13 projects on PHP 8.3+, keep secrets in server-side .env only, restrict .env to the deploy user, never commit it, and reload PHP-FPM after deploy without exposing values in logs.

Share this article

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.

Quick Contact Options
Choose how you want to connect me: