Security AWS

Gitleaks 8.30.1 on AWS User Guide

| Product: Gitleaks 8.30.1 on Ubuntu 24.04 on AWS

Overview

This guide covers launching and using the Gitleaks 8.30.1 on Ubuntu 24.04 AMI from cloudimg on Amazon EC2. It is one version of the cloudimg OWASP ZAP and Vulnerability Scanners listing on AWS Marketplace; you pick it as the software version when you subscribe and launch.

Gitleaks is the widely used open source scanner for hardcoded secrets. It reads source code, configuration files and git commit history and reports every API key, cloud access key, token, password and private key it recognises, using a ruleset compiled into the scanner. It works in two modes: gitleaks git walks the whole commit history of a repository, so a secret that was committed once and later deleted is still found, and gitleaks dir scans plain files and working trees. Results can be written as JSON or SARIF for a pipeline gate, a code review or a dashboard.

The cloudimg image adds:

  • A scheduled scan that cannot phone home. A daily timer scans a directory you choose. The scan runs as its own unprivileged gitleaks user inside a systemd sandbox with no network access at all: every address is denied, including the EC2 instance metadata service, the operating system is read-only to it, and it holds no capabilities. Gitleaks itself fetches nothing remote; its detection rules are built into the binary, so the instance can scan in a subnet with no outbound internet.
  • Reports only root can read, with secrets redacted. A report lists the secrets it found, so the scheduled scan writes its JSON and SARIF reports with mode 0600 into /var/lib/gitleaks/reports (mode 0700, owned by gitleaks). Ordinary users cannot read or even list them, and secret values are replaced with REDACTED by default. Findings keep the rule, file, line and commit.
  • Self-test fixtures unique to your instance. On first boot the instance generates its own fake, non-functional GitHub token and AWS access key id and builds three small fixtures from them (a leaky directory, a leaky git repository and a clean directory), so you can prove detection works on your own instance. No secret-shaped string is baked into the image.
  • A patched build of the scanner. The binary is compiled by cloudimg from the official Gitleaks v8.30.1 source with Go 1.26.10 and updated golang.org/x/crypto, golang.org/x/text and klauspost/compress modules, which clears 67 of the 69 Go security advisories govulncheck reports against the upstream release binary. The build provenance ships on the instance.
  • Key-only SSH (no password or keyboard-interactive login, no root login), IMDSv2 only, and a fully patched Ubuntu 24.04 LTS with unattended security upgrades switched on.

This is a command-line product: there is no web UI, no listening service, no account and no password. SSH on port 22 is the only open port.

Default user: ubuntu · Architecture: x86_64 · Recommended instance type: m5.large

Prerequisites

  • An AWS account subscribed to the listing, an EC2 key pair and a VPC subnet. Scanning needs no outbound internet access; you only need a way to get your code onto the instance (for example git clone over a NAT gateway or a VPC endpoint).
  • A security group that allows TCP 22 (SSH) from your own networks only. No other inbound port is needed.

Step 1: Launch the instance

In the AWS Marketplace listing choose Continue to Subscribe, then Continue to Configuration, pick Gitleaks 8.30.1 on Ubuntu 24.04 as the software version and your Region, then Launch through EC2. Choose m5.large, your key pair and a security group as above. Size the root volume for the code you will scan.

With the AWS CLI (replace the values in angle brackets):

aws ec2 run-instances --region <region> --image-id <ami-id-from-the-listing> \
  --instance-type m5.large --key-name <your-key-pair> \
  --security-group-ids <sg-allowing-22-from-your-network> --subnet-id <subnet-id> \
  --metadata-options HttpTokens=required,HttpEndpoint=enabled \
  --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=gitleaks}]'

Step 2: Connect to your instance

Operating system SSH user
Ubuntu 24.04 ubuntu
ssh -i <your-key.pem> ubuntu@<instance-public-ip>

There is no password to look up: /etc/gitleaks/credentials on the instance is an informational note that says so and lists the paths used below.

Step 3: Check the installation

gitleaks version
systemctl is-enabled gitleaks-scan.timer gitleaks-firstboot.service
systemctl is-active gitleaks-scan.timer
8.30.1
enabled
enabled
active

gitleaks-firstboot.service ran once on the first boot of your instance: it generated the self-test fixtures and queued a baseline scan. gitleaks-scan.timer runs the scheduled scan once a day.

Step 4: Prove detection with the self-test fixtures

Scan the leaky fixture as a directory. --redact keeps the secret values out of your terminal:

gitleaks dir --no-banner --redact /usr/share/gitleaks/fixtures/leaky; echo "exit code: $?"
6:13AM INF scanned ~176 bytes (176 bytes) in 14.2ms
6:13AM WRN leaks found: 2
exit code: 1

To see what was found, write a JSON report and list the rule, file and line of each finding:

R=$(mktemp)
gitleaks dir --no-banner --redact --log-level error --report-format json --report-path "$R" /usr/share/gitleaks/fixtures/leaky
jq -r '.[] | "\(.RuleID)  \(.File):\(.StartLine)  value: \(.Secret)"' "$R"
rm -f "$R"
aws-access-token  /usr/share/gitleaks/fixtures/leaky/config.env:3  value: REDACTED
github-pat  /usr/share/gitleaks/fixtures/leaky/config.env:2  value: REDACTED

Both values in that file are fake and were generated for your instance alone; they are not credentials for anything.

Gitleaks detecting the fake GitHub token and AWS access key id in the self-test fixture, with the values redacted

Step 5: Scan a repository's full git history

The leaky-repo fixture has a token committed to history, which only a history scan can find. gitleaks git walks every commit:

gitleaks git --no-banner --redact /usr/share/gitleaks/fixtures/leaky-repo; echo "exit code: $?"
6:13AM INF 1 commits scanned.
6:13AM INF scanned ~149 bytes (149 bytes) in 307ms
6:13AM WRN leaks found: 1
exit code: 1

A history finding names the commit, the author and the date as well as the file:

R=$(mktemp)
gitleaks git --no-banner --redact --log-level error --report-format json --report-path "$R" /usr/share/gitleaks/fixtures/leaky-repo
jq -r '.[] | "\(.RuleID)  \(.File):\(.StartLine)  commit \(.Commit[0:12])  \(.Author)  \(.Date)"' "$R"
rm -f "$R"
github-pat  settings.py:2  commit b460ca0f76cb  cloudimg self-test  2026-10-20T06:09:49Z

To scan one of your own repositories, point gitleaks git at its path:

gitleaks git --redact /path/to/your/repo

Step 6: Confirm a clean scan reports nothing

gitleaks dir --no-banner /usr/share/gitleaks/fixtures/clean; echo "exit code: $?"
6:13AM INF scanned ~165 bytes (165 bytes) in 3.96ms
6:13AM INF no leaks found
exit code: 0

Step 7: The scheduled scan and its reports

The scheduled scan reads /etc/gitleaks/scan.conf, scans SCAN_TARGET (default /srv/projects) with gitleaks dir, and writes a JSON and a SARIF report plus latest.json and latest.sarif links. Run one now and read its log:

sudo systemctl start gitleaks-scan.service
sudo journalctl -u gitleaks-scan.service -n 8 --no-pager -o cat
gitleaks-scan-run: scanning /srv/projects for hardcoded secrets (redaction 100%)
6:13AM INF scanned ~0 bytes (0) in 3.51ms
6:13AM INF no leaks found
gitleaks-scan-run: no leaks found
gitleaks-scan-run: reports: /var/lib/gitleaks/reports/gitleaks-scan-20261020T061345Z.json | /var/lib/gitleaks/reports/gitleaks-scan-20261020T061345Z.sarif (latest.json / latest.sarif updated)
gitleaks-scan.service: Deactivated successfully.
Finished gitleaks-scan.service - Scheduled Gitleaks secret scan of SCAN_TARGET (cloudimg).
gitleaks-scan.service: Consumed 1.649s CPU time.

The reports belong to the gitleaks user and only root can read them:

sudo ls -l /var/lib/gitleaks/reports/
-rw------- 1 gitleaks gitleaks     3 Oct 20 06:13 gitleaks-scan-20261020T061345Z.json
-rw------- 1 gitleaks gitleaks 48983 Oct 20 06:13 gitleaks-scan-20261020T061345Z.sarif
lrwxrwxrwx 1 gitleaks gitleaks    35 Oct 20 06:13 latest.json -> gitleaks-scan-20261020T061345Z.json
lrwxrwxrwx 1 gitleaks gitleaks    36 Oct 20 06:13 latest.sarif -> gitleaks-scan-20261020T061345Z.sarif

As the ubuntu user without sudo, the directory is closed:

$ ls /var/lib/gitleaks/reports
ls: cannot access '/var/lib/gitleaks/reports': Permission denied

Read a report with sudo; latest.json is a JSON array of findings (empty when nothing was found) and latest.sarif is SARIF 2.1.0, which GitHub code scanning, GitLab and most IDEs import directly:

sudo jq length /var/lib/gitleaks/reports/latest.json
sudo jq '.runs[0].tool.driver.name' /var/lib/gitleaks/reports/latest.sarif
0
"gitleaks"

The scheduled scan running as the gitleaks user and its 0600 reports

The scan exits 1 when it finds leaks; systemd treats that as a normal result, and the journal line LEAKS FOUND - see <report> tells you which report to open. To collect reports from another system, copy them off as root (for example sudo cp into a directory you control) and decide there whether they may leave the instance.

Step 8: Scan your own code

Put your checkouts under /srv/projects, or point SCAN_TARGET at where they already live. The scheduled scan runs as the gitleaks user, so everything it should scan must be readable by that user: files 0644 and directories 0755, or group gitleaks. The scan logs a WARNING with the number of entries it could not read rather than reporting "no leaks" for them.

cd /srv/projects
sudo git clone https://github.com/<your-org>/<your-repo>.git
sudo systemctl start gitleaks-scan.service
sudo jq -r '.[] | "\(.RuleID)  \(.File):\(.StartLine)"' /var/lib/gitleaks/reports/latest.json

For a one-off scan of something else, run Gitleaks directly as your own user, for example gitleaks git --redact ~/work/repo or gitleaks dir --redact ~/work/tree.

Step 9: The exit code contract for CI

Gitleaks exits 0 when it finds nothing and 1 when it finds leaks, which is what makes it usable as a merge gate:

gitleaks dir --no-banner /usr/share/gitleaks/fixtures/clean >/dev/null 2>&1; echo "clean fixture exit: $?"
gitleaks dir --no-banner /usr/share/gitleaks/fixtures/leaky >/dev/null 2>&1; echo "leaky fixture exit: $?"
clean fixture exit: 0
leaky fixture exit: 1
Exit code Meaning
0 No leaks found
1 Leaks found
anything else The scan did not complete

Exit codes for a clean and a leaky scan, and the scheduled scan configuration

Step 10: What the scan can reach

The scheduled scan's sandbox is set in its systemd unit:

systemctl show -p User -p IPAddressDeny -p ProtectSystem -p ProtectHome -p NoNewPrivileges -p CapabilityBoundingSet gitleaks-scan.service
IPAddressDeny=::/0 0.0.0.0/0
CapabilityBoundingSet=
User=gitleaks
ProtectHome=read-only
ProtectSystem=strict
NoNewPrivileges=yes

IPAddressDeny=::/0 0.0.0.0/0 is how systemd reports the unit's two deny rules, the instance metadata service (169.254.169.254) and every other address: the scan cannot open any network connection, so a malicious file in a scanned repository cannot use it to reach the instance metadata service or anything else. The first boot unit carries the same rules. The only path the scan may write to is /var/lib/gitleaks, so keep REPORT_DIR under it. Gitleaks needs no network for scanning; only your own git clone or git pull, run as your own user, does.

Step 11: Configuration

grep -v '^#' /etc/gitleaks/scan.conf | grep .
SCAN_TARGET="/srv/projects"
REPORT_DIR="/var/lib/gitleaks/reports"
REDACT_PERCENT=100
GITLEAKS_CONFIG=""
REPORT_RETENTION_DAYS=30
  • SCAN_TARGET: the directory the daily scan walks with gitleaks dir.
  • REPORT_DIR and REPORT_RETENTION_DAYS: where reports go (keep it under /var/lib/gitleaks) and how many days of dated reports are kept.
  • REDACT_PERCENT: how much of each secret value is replaced in reports and logs. 100 (the default) replaces all of it. Set 0 only if a downstream tool needs the raw value; the reports then hold live secrets.
  • GITLEAKS_CONFIG: empty uses the ruleset built into Gitleaks. Set it to a .toml file readable by the gitleaks user to use your own rules.

The file is read at the start of every scan, so a change takes effect on the next scan. Edit it with sudo nano /etc/gitleaks/scan.conf. To change the schedule, add a drop-in with sudo systemctl edit gitleaks-scan.timer (for example OnCalendar=hourly).

Custom rules. A config that keeps the default ruleset and adds one rule of your own:

# /etc/gitleaks/gitleaks.toml  (mode 0644)
[extend]
useDefault = true

[[rules]]
id = "example-corp-api-key"
description = "Example Corp internal API key"
regex = '''excorp_[a-z0-9]{32}'''
keywords = ["excorp_"]

Then set GITLEAKS_CONFIG="/etc/gitleaks/gitleaks.toml" in scan.conf. You can also pass --config <path> to any gitleaks dir or gitleaks git run.

Step 12: How the scanner on this image was built

cat /usr/share/gitleaks/build-provenance/BUILD-PROVENANCE.txt
Gitleaks 8.30.1 on this image was compiled by cloudimg from the unmodified upstream source at
https://github.com/gitleaks/gitleaks.git commit 83d9cd684c87d95d656c1458ef04895a7f1cbd8e (tag v8.30.1), with the module bumps below to clear Go security
advisories. Licence: MIT (/usr/share/gitleaks/LICENSE.upstream). Copyright (c) 2019 Zachary Rice.

toolchain     go1.26.10 linux/amd64, https://go.dev/dl/go1.26.10.linux-amd64.tar.gz sha256 ccfe7ae822d2c2f41f4fe7c956199967a4dac22d0ee0d2b2bfdb440aab3b20c5
modules       go get golang.org/x/crypto@v0.57.0 golang.org/x/text@v0.42.0 github.com/klauspost/compress@v1.18.7 (module proxy + sum.golang.org);
              minimum version selection also raised x/sync v0.23.0, x/sys v0.48.0 and the go directive
              to 1.26.0 -- exactly the lines in go.mod.diff, guarded at build
flags         CGO_ENABLED=0 go build -trimpath -tags gore2regex
              -ldflags "-s -w -X=github.com/zricethezav/gitleaks/v8/version.Version=8.30.1"
govulncheck   v1.9.0 -mode=binary on the compiled binary: GO-2025-4020 GO-2026-5932
              (GO-2026-5932 = golang.org/x/crypto/openpgp, no fixed version exists;
               GO-2025-4020 = rardecode RAR DoS, reachable only with --max-archive-depth > 0)
upstream      release binary gitleaks_8.30.1_linux_x64.tar.gz sha256 551f6fc83ea457d62a0d98237cbad105af8d557003051f41f3e7ca7b3f2470eb
              (go1.24.11; 69 govulncheck advisories; not shipped)

The two remaining advisories do not affect default use: no fixed version of golang.org/x/crypto/openpgp exists, and the RAR one needs archive scanning, which is off unless you pass --max-archive-depth. If you enable archive scanning, scan only archives you trust. The same directory holds the module list compiled into the binary (buildinfo.txt), the exact go.mod change (go.mod.diff) and the full govulncheck report.

Step 13: Access to the instance

sudo sshd -T | grep -E '^(passwordauthentication|kbdinteractiveauthentication|permitrootlogin|pubkeyauthentication) '
permitrootlogin no
pubkeyauthentication yes
passwordauthentication no
kbdinteractiveauthentication no

SSH accepts only the key pair you chose at launch (/etc/ssh/sshd_config.d/10-cloudimg-key-only.conf), and no account on the image has a password. Nothing else listens on a public address.

Step 14: Components

Component Path
Gitleaks binary /usr/local/bin/gitleaks
Scheduled scan runner /usr/local/bin/gitleaks-scan-run
Scan unit and timer /etc/systemd/system/gitleaks-scan.service, /etc/systemd/system/gitleaks-scan.timer
Configuration /etc/gitleaks/scan.conf
Reports /var/lib/gitleaks/reports (gitleaks, mode 0700)
Self-test fixtures /usr/share/gitleaks/fixtures (regenerate with sudo /usr/local/sbin/gitleaks-selftest-fixtures)
First boot script /usr/local/sbin/gitleaks-firstboot.sh
Build provenance and licence /usr/share/gitleaks/build-provenance/, /usr/share/gitleaks/LICENSE.upstream
Key-only SSH drop-in /etc/ssh/sshd_config.d/10-cloudimg-key-only.conf

Step 15: Security recommendations

  • Allow port 22 in the security group from your own networks only.
  • Keep REDACT_PERCENT=100 unless a tool genuinely needs the raw values, and treat every report as sensitive either way: it says where your secrets are.
  • Rotate any real secret Gitleaks finds. Removing it from the latest commit is not enough while it is still in the git history.
  • Keep the operating system patched; unattended security upgrades are on, and sudo apt-get update && sudo apt-get upgrade applies everything else. New Gitleaks releases arrive as new versions of this listing.

Support and licensing

Gitleaks is open source under the MIT licence (Copyright (c) 2019 Zachary Rice; a copy is at /usr/share/gitleaks/LICENSE.upstream). There is no per user or per CPU licence fee. The AMI price covers cloudimg's hardening, first boot setup and support.

  • Email: support@cloudimg.co.uk
  • Website: https://www.cloudimg.co.uk
  • Support: 24/7, with a 24 hour response SLA