Secret scanning
A password or API token committed to Git stays in the history after someone deletes the line, so catch it before it merges. This page is for developers and leads on a project built from Vortex. It shows how to run the secret scan locally, scan the Git history, ignore a false positive and read the findings in continuous integration (CI).
Gitleaks scans the code for hardcoded secrets such as passwords, API keys and tokens, and fails the security audit when it finds a secret.
Usage
Vortex doesn't install Gitleaks locally, so install it on your system first; see the Gitleaks installation instructions. Then run the scan from the project root:
gitleaks dir .
Gitleaks reads .gitleaks.toml from the directory it scans, so run the
command from the project root. By default, it prints only the number of
findings. Add -v to see each finding. On a clean codebase, the scan ends
with no leaks found.
Like CI, gitleaks dir scans the files on disk and skips the Git history.
To scan the commits too, see
Scan the Git history.
Configuration
Global configuration lives in the
.gitleaks.toml
file at the repository root; see the Gitleaks configuration
documentation. The
file extends the Gitleaks default rule set. It allowlists the following
paths, which hold third-party, generated or local-only files:
.artifacts/.data/.git/.logs/node_modules/vendor/web/core/web/libraries/web/modules/contrib/web/sites/default/files/web/themes/contrib/
Each pattern matches its directory at any depth. With those paths skipped, the scan covers the code your team writes, so a clean install reports 0 findings while Gitleaks still detects real secrets.
Ignore findings
To ignore a single line you can edit, add a gitleaks:allow comment to it.
Gitleaks skips every finding on a line that contains the comment, so the
exception moves with the line:
$settings['example'] = 'not-a-real-secret'; // gitleaks:allow
For other exceptions, use 1 of the following:
- To ignore a path or a known-safe value that recurs across the codebase,
add an allowlist entry to the
.gitleaks.tomlfile. - For a line that can't hold a comment, such as a line in a JSON file, use
a
.gitleaksignorefile at the repository root. Add the finding's fingerprint to that file. The fingerprint holds the file, the rule and the line number, so it stops matching when the line moves.
Copy the fingerprint from the Fingerprint: line that gitleaks dir . -v
prints for the finding. The file takes 1 fingerprint per line and skips
blank lines and lines that start with #:
# Fake token in a Behat fixture.
tests/behat/fixtures/response.json:generic-api-key:3
Confirm that the exception works: run gitleaks dir . -v again and check
that the finding no longer appears. When it was the only finding, the scan
ends with no leaks found.
Scan the Git history
The CI scan reads the files in the checkout. A secret committed in 1 commit
and deleted in the next passes that scan, but anyone with a clone can still
read it from the history. gitleaks git scans the lines each commit added,
so it finds those secrets too.
A history scan gives the same answer for the same commits and rules, so CI
doesn't run it on every build. Run it yourself at the points in the
following sections. Run it from the project root, so Gitleaks reads
.gitleaks.toml and .gitleaksignore the same way gitleaks dir does.
Onboarding scan
Scan the full history once when you add secret scanning to a repository that already has commits, for example when you adopt Vortex on an existing project:
gitleaks git . -v --redact
--redact replaces each matched secret with REDACTED in the output. The
rest of the source line still appears, so treat the output as sensitive and
don't share it. The output also shows the file, line, commit and
fingerprint of each finding.
Gitleaks scans only the commits and branches present in your clone. A clone
made with git clone --depth holds part of the history and 1 branch, so
clone the repository again without --depth before you scan.
Handle each finding as described in
Handle a finding in the history.
Then run the scan again and confirm that it ends with no leaks found.
Ad hoc scans
Scan the history again in these cases:
-
Before you merge a branch where a secret might have been committed and then removed. Check out the branch, then pass a Git revision range to
--log-optsto scan only its commits:gitleaks git . -v --redact --log-opts="origin/main..HEAD"Replace
origin/mainwith your default branch.HEADis the checked-out branch, so the range is empty when you run the scan from the default branch. -
Before you make a private repository public. Every commit becomes readable, including commits that exist only in closed pull requests. GitHub keeps those under
refs/pull/, so fetch every branch, every tag and those refs before you scan the full history:git fetch --tags origingit fetch origin "+refs/pull/*:refs/remotes/origin/pull/*" -
After a Gitleaks upgrade or a rule change in
.gitleaks.toml. A new rule can match content in old commits, and only a history scan checks them.
Handle a finding in the history
A secret in the history stays exposed for as long as the credential works. To close the exposure, rotate the credential:
- Revoke the credential with the service that issued it.
- Create a new credential.
- Update every place that uses the credential.
Don't rewrite the history to remove the secret. A rewrite leaves the secret in existing clones, forks, CI caches and the hosting provider's pull request references. After rotation, the old value in the history no longer grants access.
After you rotate the credential, add the finding's fingerprint to
.gitleaksignore as described in Ignore findings, so
later history scans pass. A history fingerprint starts with the commit
hash, so it matches the finding in that commit only:
# GitHub token revoked and rotated.
06d02de9fdcbeac96844a410462a26f3fc5c9004:web/sites/default/settings.php:github-pat:2
Continuous integration
Gitleaks runs from its official Docker image in the security audit
workflow and fails
that workflow when it finds a secret. The installer turns the scan on by
default. Answering no at its
Scan for committed secrets with Gitleaks? prompt removes the CI steps
and the .gitleaks.toml file.
Ignore failures
Set VORTEX_CI_GITLEAKS_IGNORE_FAILURE to 1 to let the workflow pass
anyway. In GitHub Actions, set it as a repository variable. In CircleCI,
set it as an environment variable. Gitleaks still runs and reports how
many findings it made. In GitHub Actions, the details reach code scanning
and the security-findings artifact. In CircleCI, run gitleaks dir . -v
locally to see them.
➡️ See Ignore tool failures.
Where findings appear
In GitHub Actions, the workflow also uploads Gitleaks findings to the
repository's Security > Code scanning tab under the gitleaks category.
Each finding becomes an alert naming the rule that matched, located at the
line it was found on.
➡️ See Code scanning.
Dismiss a finding
Dismissing an alert in the Security > Code scanning tab records a reason against that finding and removes it from the open list. Dismiss an alert to track an assessment.
Dismissing leaves the scan unchanged. Gitleaks still matches the value and still fails the workflow until you ignore it as described in Ignore findings. That takes 1 of the following:
- A
gitleaks:allowcomment on the line - An allowlist entry in
.gitleaks.toml - The finding's fingerprint in
.gitleaksignore