Open-Source Wikis

/

Gitleaks

/

Gitleaks

/

Architecture

gitleaks/gitleaks

Architecture

Gitleaks is a single-binary CLI built on Cobra. All scan modes share one detection pipeline: a sources.Source produces sources.Fragment values, the detect.Detector runs every configured rule against each fragment, and a report.Reporter writes the findings.

Top-level layout

gitleaks/
├── main.go                # entry point, calls cmd.Execute()
├── cmd/                   # Cobra commands: git, dir, stdin, detect, protect, version
│   ├── root.go            # persistent flags, Detector construction
│   ├── git.go             # `gitleaks git ...`
│   ├── directory.go       # `gitleaks dir ...`
│   ├── stdin.go           # `gitleaks stdin`
│   ├── detect.go          # legacy hidden command
│   ├── diagnostics.go     # CPU/mem/trace pprof, http pprof
│   ├── scm/               # SCM platforms (GitHub, GitLab, …) for finding links
│   └── generate/          # offline tool that regenerates config/gitleaks.toml
├── config/                # rule + allowlist parsing, default config
│   └── gitleaks.toml      # embedded default rules (~220 rules)
├── detect/                # detection engine
│   ├── detect.go          # Detector type, DetectContext, rule loop
│   ├── baseline.go        # ignore findings already in a baseline report
│   ├── codec/             # base64/hex/percent decoding for nested secrets
│   ├── files.go, git.go   # deprecated wrappers (kept for v8 API stability)
│   ├── reader.go          # streaming reader → Detector
│   └── utils.go           # entropy, link generation, terminal printing
├── sources/               # sources of fragments
│   ├── git.go             # `git log -p` / `git diff` parsing
│   ├── files.go           # filesystem walker
│   ├── file.go            # single file/stream + archive extraction
│   └── fragment.go        # the Fragment type
├── report/                # output formats: json, csv, junit, sarif, template
├── regexp/                # build-tag selectable regex backend (stdlib vs go-re2)
├── logging/               # zerolog wrapper
└── version/               # ldflags-injected version string

Data flow

The scan pipeline is simple: a Source yields Fragments, and the Detector checks each fragment against every rule.

graph LR
    User["gitleaks git/dir/stdin"] --> Cmd["cmd/*.go"]
    Cmd -->|builds| Cfg[config.Config]
    Cmd -->|builds| Det[detect.Detector]
    Cmd -->|chooses| Src[sources.Source]
    Src -->|sources.Fragment| Det
    Det -->|rules + allowlists| Det
    Det -->|report.Finding| Out[report.Reporter]
    Out --> File[report file<br/>json/csv/sarif/...]
    Det -->|verbose| TUI[stdout pretty-print]

sources.Source is a one-method interface (sources/source.go):

type Source interface {
    Fragments(ctx context.Context, yield FragmentsFunc) error
}

Three concrete implementations exist:

  • sources.Git (sources/git.go) parses the streaming output of git log -p (or git diff) using gitleaks/go-gitdiff. For binary blobs that look like archives, it streams the blob via git cat-file blob and feeds it back through sources.File.
  • sources.Files (sources/files.go) does a filepath.WalkDir and turns every readable file into a sources.File.
  • sources.File (sources/file.go) reads a single io.Reader in 100KB chunks, splitting on whitespace boundaries to avoid cutting secrets in half. It also detects archive types via mholt/archives and recurses into them up to --max-archive-depth.

Detection loop

Detector.DetectContext (detect/detect.go) does the actual work for one fragment:

graph TD
    F[Fragment] --> A{File path or commit<br/>in global allowlist?}
    A -->|yes| Skip[return]
    A -->|no| K[Aho-Corasick prefilter:<br/>which rule keywords appear?]
    K --> R[for each rule]
    R --> M{Rule keywords match<br/>or rule has none?}
    M -->|no| R
    M -->|yes| Re[apply rule.Regex]
    Re --> S{secretGroup, entropy,<br/>allowlists pass?}
    S -->|no| R
    S -->|yes| Add[append finding]
    Add --> R
    R -->|done| D{depth < MaxDecodeDepth<br/>and segments found?}
    D -->|yes| Dec[codec.Decode<br/>recurse]
    Dec --> R
    D -->|no| End[filter & redact]

Two performance choices show up here:

  • Keyword pre-filter. All rules' keywords are compiled into a single Aho-Corasick trie at Detector construction time (prefilter in detect/detect.go). Each fragment is matched against the trie once, and a rule's regex only runs if at least one of its keywords matched. This avoids running ~220 regexes against every line.
  • Concurrency. A semgroup.Group (fatih/semgroup) caps fragment-level concurrency at 40. Each sources.Source schedules its work onto this shared semaphore.

Build-time pluggable regex engine

The regexp/ package picks a regex backend at compile time using a build tag:

Build tag Backend File
(default) Go's standard regexp (RE2-based, pure Go) regexp/stdlib_regex.go
gore2regex wasilibs/go-re2 — RE2 via WebAssembly for higher throughput regexp/wasilibs_regex.go

Every package that compiles regexes does so through regexp.MustCompile from this internal package, never the standard library directly.

Config lifecycle

graph LR
    Default[config/gitleaks.toml<br/>go:embed in config/config.go]
    User[user-supplied .gitleaks.toml]
    Env[GITLEAKS_CONFIG_TOML env var]
    Default --> Viper[viper.ReadConfig]
    User --> Viper
    Env --> Viper
    Viper --> VC[ViperConfig struct]
    VC -->|.Translate| Cfg[config.Config<br/>compiled regexes,<br/>Aho-Corasick trie of keywords]
    Cfg --> Det[detect.Detector]

The default ruleset is generated offline by cmd/generate/config/main.go, which assembles ~220 individual rule files from cmd/generate/config/rules/*.go into the embedded config/gitleaks.toml. See Rule generation for how to add a new rule.

Outputs

report.Reporter is implemented by:

  • report.JsonReporter — default for many users
  • report.CsvReporter
  • report.JunitReporter
  • report.SarifReporter — the format consumed by GitHub code scanning
  • report.NewTemplateReporter — Go text/template (with Masterminds/sprig) for arbitrary output

The reporter is selected from --report-format (or inferred from --report-path extension). See systems/report.

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

Architecture – Gitleaks wiki | Factory