Open-Source Wikis

/

Gitleaks

/

Features

/

Archive scanning

gitleaks/gitleaks

Archive scanning

Recursively extract zip/tar/7z and other archive types and scan their contents. Enabled by --max-archive-depth=N (default 0 = disabled).

Why it's off by default

Archive scanning can multiply scan time significantly — a single 100MB tarball might contain thousands of files. The feature is opt-in to keep default scans fast.

How it works

sources.File (sources/file.go) is the workhorse for any single io.Reader. When it sees one, it asks mholt/archives whether the content looks like a known archive format:

format, _, err := archives.Identify(ctx, s.Path, nil)
if err == nil && format != nil {
    // archive!
}

If it is an archive, and the current archiveDepth + 1 ≤ MaxArchiveDepth, the source extracts it and constructs a child File source per inner file:

graph TD
    Outer[outer file: archive.tar.gz] --> Id[archives.Identify → tar.gz]
    Id --> Decompressor[gzip Decompressor]
    Decompressor --> Inner[tar inner reader]
    Inner --> Inner2[archives.Identify → tar]
    Inner2 --> Extractor[tar Extractor]
    Extractor --> Files[per-file callback]
    Files --> Recurse[new File source<br/>archiveDepth += 1]
    Recurse -->|archive again?| Id2[archives.Identify…]
    Recurse -->|no| Frag[normal fragment scan]

Two helpers handle the two archive flavors:

  • extractorFragments — for archive containers (zip, tar, 7z, rar, etc.) that contain multiple files. Each inner file becomes a new File with archiveDepth incremented.
  • decompressorFragments — for single-stream compression (gzip, bzip2, xz, lzip, brotli, …). The decompressed stream is fed back into fileFragments directly without bumping depth.

Inner paths

Inside the archive, a leak's path is reported with ! (defined as InnerPathSeparator in sources/file.go) joining each level:

File:        testdata/archives/nested.tar.gz!archives/files.tar!files/.env.prod

This means: .env.prod is inside files.tar, which is inside archives.tar.gz, in the testdata directory. File.FullPath() constructs this string by joining outerPaths (forward-slash normalized) with the current Path.

In the git source

sources.Git (sources/git.go) special-cases binary files that look like archives. When gitdiff.IsBinary is true and isArchive(ctx, gitdiffFile.NewName) returns true, the git source streams the blob via git cat-file blob <commit>:<path> and pipes it through a File source. This means:

  • gitleaks git --max-archive-depth=2 will recurse into archives committed to history.
  • The blob is read lazily through a blobReader (a wrapper around the git cat-file process's stdout).

The blobReader.Close() carefully drains and waits to avoid zombie processes.

Format support

Whatever mholt/archives supports. As of the current dependency version (v0.1.2):

  • Compression formats: brotli, bzip2, gzip, lz4, lzip, snappy, sz, xz, zlib, zstd
  • Archive formats: 7z, rar, tar, zip

If archives.Identify can't determine the format, the file is scanned as plain content (the error is swallowed — see s.Fragments in file.go).

Format identification with seekers

A few archive formats (notably 7-zip and zip) need a seekable reader. If the underlying reader doesn't satisfy io.Seeker and io.ReaderAt, the source spills the content to a temp file via os.CreateTemp("", "gitleaks-archive-"), copies the data, and feeds the temp file to the extractor. The temp file is removed on exit.

Tuning

--max-archive-depth=1 enables a single level of recursion. =0 (the default) disables it entirely. Higher values are bounded by the archive nesting in your data — recursion stops naturally when a layer doesn't look like an archive.

A warning is logged once per attempted-but-blocked archive when the feature is enabled but depth is exceeded. When the feature is disabled, the same condition logs at trace level instead, keeping the output quiet.

  • systems/sourcesFile, Files, and Git source details
  • Decoding — a different kind of recursion (encoded substrings rather than nested files)

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Archive scanning – Gitleaks wiki | Factory