Configuration

June 25, 2026 · View on GitHub

keyhog runs with zero configurationkeyhog scan . works out of the box on the canonical tuned defaults. Everything on this page is optional override.

Precedence

Settings resolve in this order, rightmost winning:

compiled defaults  →  .keyhog.toml  →  CLI flags
(ScanConfig::default)  (walked up from    (always win)
                        the scan path)
  • Compiled defaults live in one place: ScanConfig::default() in crates/core/src/config.rs. They are the tuned == benched == shipped values — the same numbers the SecretBench leaderboard is measured on. The unit test crates/core/tests/unit/config.rs pins them, so a change to a shipped default is a deliberate, test-gated decision.
  • .keyhog.toml is discovered by walking up from the scan path to the filesystem root (first one found wins). Copy .keyhog.toml.example to your repo root and delete what you don't need. A malformed .keyhog.toml fails closed with the path and TOML error before any scan output is written. Unknown tables and keys are parse failures, not ignored compatibility shims. Use --no-config when you intentionally want compiled defaults.
  • CLI flags always override the file. A flag left unset falls through to the file, then to the compiled default.

There is no separate system/user config tier today: the walk-up .keyhog.toml is the only file layer.

Core settings

Each row is the same knob across all three layers. Defaults are ScanConfig::default().

SettingDefault.keyhog.toml keyCLI flagEffect
Min confidence0.40min_confidence--min-confidenceDrop findings scoring below this (0.0–1.0). Bench-tuned for max F1.
Decode depth10decode_depth--decode-depthMax recursive decode passes, e.g. base64(hex(url(secret))) (1–10).
Decode size limit512KBdecode_size_limit--decode-size-limitPer-file ceiling for decode-through; larger files skip encoding detection.
Entropy enabledonno_entropy = true disables--no-entropyShannon-entropy detection for novel high-entropy strings.
Entropy in sourceoffentropy_source_files--entropy-source-filesRun entropy inside .py/.js/.go/… (off by default to cut FPs).
Entropy threshold4.5entropy_threshold--entropy-thresholdBits/byte cutoff (3.5 aggressive … 5.5 conservative).
Entropy min length16min_secret_len--min-secret-lenMinimum credential length for entropy-fallback candidates. Named detectors keep their own shape-specific length gates.
Keyword low-entropyongeneric_keyword_low_entropy--no-keyword-low-entropyAdmit credential-keyword-anchored values (PASSWORD=, *_PASS=, secret: …) on a low entropy floor; precision is carried by the ML model. Surfaces real-world config passwords. Disabling raises precision but drops real recall.
ML enabledonno_ml = true disables--no-mlML confidence gating. Disabling raises FPs and hurts recall.
ML weight0.5ml_weight--ml-weightBlend weight of the ML score vs heuristics (0.0–1.0).
Unicode normonno_unicode_norm = true disables--no-unicode-normNormalise homoglyphs before matching (anti-evasion).
Scan commentsoff--scan-commentsTreat secrets in code comments at full confidence (default downgrades them).
Threads#coresthreads--threadsParallel scan workers.
Reader threadsscan-pool-derivedreader_threads--reader-threadsDedicated filesystem read workers.
Fused batch32fused_batch--fused-batchChunk batch size for the fused filesystem pipeline.
Fused depthworker-count-derivedfused_depth--fused-depthBounded channel depth for fused filesystem batches.
Per-chunk timeoutoffper_chunk_timeout_ms--per-chunk-timeout-msOptional hard deadline per chunk scan in milliseconds.
Dedup scopecredentialdedup--dedupcredential / file / none.
Max file size100 MiBmax_file_size--max-file-sizeWalker skips files larger than this.
Severity floor(all)severity--severityMinimum severity to report: info/low/medium/high/critical.
Output formattextformat--formattext/json/jsonl/sarif/csv/github-annotations/gitlab-sast/html/junit.
Show secretsoffshow_secrets--show-secretsPrint plaintext credentials. Never enable in CI/logs.
Incremental cacheoffincremental / incremental_cache--incremental / --incremental-cacheBLAKE3 Merkle skip-cache; 10–100× on CI re-runs.
Hyperscan cache dirplatform cache dir[system] cache_dir--cache-dirCompiled-database cache directory. Must be an absolute user-owned path under the home directory or per-user keyhog temp cache root.
Autoroute cache fileplatform cache file[system] autoroute_cache--autoroute-cachePersisted fastest-correct backend decisions. Use an absolute file path or off to disable persistence and force auto-route cache misses to fail loudly.
Bayesian calibration cacheoff[system] calibration_cache--calibration-cacheExplicit per-detector confidence calibration file written by keyhog calibrate. Missing or damaged explicit files fail closed before scanning.
GPU runtime policyauto[system] gpu--no-gpu / --require-gpuauto probes when routing can use GPU, off skips GPU init, and required fails closed when no usable GPU stack is available. Printed by keyhog config --effective and included in autoroute scan identity.
Autoroute GPU candidatesoff[system] autoroute_gpu--autoroute-gpu / --no-autoroute-gpuAllows calibration to include GPU candidates for eligible workload buckets. Normal scans still require persisted fastest-correct evidence; this never benchmarks during production scans.
Coalesced batch pipelineoff[system] batch_pipeline--batch-pipeline / --no-batch-pipelineDiagnostic/calibration route that bypasses the fused filesystem pipeline. Printed by keyhog config --effective and included in autoroute scan identity.
AWS canary issuer extensionsembedded baseline[aws] canary_accounts / knockoff_accountsExtra 12-digit AWS account IDs treated as canary-token issuers during offline access-key metadata classification and verification suppression.
Scanner tuningcompiled scanner defaults[tuning]Detection/recall route gates that affect engine work selection. These are explicit config so autoroute calibration identity includes them; ambient KEYHOG_* tuning env vars are ignored.
Backendauto--backendauto/gpu/gpu-region-presence/mega-scan/megascan/gpu-mega-scan/simd/simd-regex/cpu/cpu-fallback. Auto uses a persisted installer-calibrated fastest-correct decision for the exact workload bucket; missing/stale/incomplete calibration is an error, not permission to substitute another backend.

Source limits

Source byte/count ceilings resolve through the same precedence chain: compiled SourceLimits::default().keyhog.toml [limits] → CLI --limit-* flags.

LimitDefault.keyhog.toml keyCLI flag
Stdin bytes10 MiB[limits] stdin_bytes--limit-stdin-bytes
Web response bytes10 MiB[limits] web_response_bytes--limit-web-response-bytes
S3 object bytes10 MiB[limits] s3_object_bytes--limit-s3-object-bytes
GCS object bytes10 MiB[limits] gcs_object_bytes--limit-gcs-object-bytes
Azure blob bytes10 MiB[limits] azure_blob_bytes--limit-azure-blob-bytes
Cloud listed objects100000[limits] cloud_max_objects--limit-cloud-max-objects
Docker tar entry bytes128 MiB[limits] docker_tar_entry_bytes--limit-docker-tar-entry-bytes
Docker config/manifest bytes16 MiB[limits] docker_image_config_bytes--limit-docker-image-config-bytes
Docker tar total bytes8 GiB[limits] docker_tar_total_bytes--limit-docker-tar-total-bytes
Git stdout line bytes10 MiB[limits] git_line_bytes--limit-git-line-bytes
Git aggregate bytes256 MiB[limits] git_total_bytes--limit-git-total-bytes
Git blob bytes10 MiB[limits] git_blob_bytes--limit-git-blob-bytes
Git emitted chunks500000[limits] git_chunks--limit-git-chunks
Hosted-git listing pages1000[limits] hosted_git_pages--limit-hosted-git-pages
Binary strings bytes64 MiB[limits] binary_read_bytes--limit-binary-read-bytes
Ghidra output bytes50 MiB[limits] binary_decompiled_bytes--limit-binary-decompiled-bytes

Library note — ScanConfig::max_file_size and ScanConfig::dedup are scan pipeline settings, not regex-engine settings. The CLI applies them through the filesystem source and final deduplication stage; FilesystemSource::new uses the same DEFAULT_MAX_FILE_SIZE_BYTES as ScanConfig::default() so the shipped default cannot drift.

Presets

PresetTOMLCLIWhat it does
Fastfast = true--fastPattern-match only — disables decode + entropy + ML. Fastest; largest blind spot. Refused under --lockdown.
Deepdeep = true--deepEverything on, maximum recall.
Precision--precisionHigh-precision mass scanning: drops entropy-only/ML-speculative findings, raises the confidence floor to 0.85, shallow decode. Stays fully offline and fast.

--fast, --deep, and --precision are mutually exclusive and conflict with --no-decode/--no-entropy.

A preset is a BASE, not a terminal state. It seeds the decode/entropy/ML defaults, then any explicit knob you pass on the same command line overrides that base — --deep --decode-depth 3 runs the deep base at decode-depth 3, and --deep --min-confidence 0.9 raises the floor on the deep base. Two overrides are one-directional and cannot weaken a precision bar: under --precision, --min-confidence may raise the 0.85 floor but never lower it, and --no-keyword-low-entropy can only disable the relaxed keyword floor, never re-enable it under a preset that turned it off. Everything else takes effect as written.

Nested tables

.keyhog.toml also accepts nested tables. They must appear after all flat top-level keys (a TOML rule). Where a nested key and its flat twin both set a value, the flat form wins.

[scan]

A readable grouping for the scan scalars (severity, min_confidence, decode_depth, format, exclude, threads, reader_threads, fused_batch, fused_depth, per_chunk_timeout_ms, dedup) — exactly equivalent to setting each one flat at the top level, and the form the rest of the docs show for readability. Pick one form per key: if the same key is set both ways, the flat top-level value wins (per Nested tables above).

[scan]
severity = "high"
min_confidence = 0.40       # raise toward 0.85 for fewer false positives
decode_depth = 10           # 1-10, same ceiling as --decode-depth
exclude = ["**/test/fixtures/**", "vendor/"]
threads = 8
reader_threads = 2
fused_batch = 32
fused_depth = 4
per_chunk_timeout_ms = 30000

[detector.<id>] — per-detector overrides

Keyed by detector id (keyhog detectors lists them; keyhog explain <id> shows one):

[detector.generic-api-key]
enabled = false             # drop this detector from the corpus entirely

[detector.twilio-api-key]
min_confidence = 0.6        # per-detector floor — OVERRIDES the global one

There are three per-detector floor sources, in increasing precedence:

  1. Tier-Bmin_confidence inside the detector's own TOML under detectors/<id>.toml ([detector] min_confidence). The detector's shipped baseline.
  2. Tier-A compiledSHIPPED_DETECTOR_FLOORS in crates/cli/src/config.rs. Ships in the binary and applies on every run, including the no-config bench/default path, so a noisy detector can be reined in without authoring a TOML.
  3. .keyhog.toml [detector.<id>] min_confidence — operator intent; overrides the compiled floor for that id.

enabled = false removes a detector on any path; a file enabled = true cannot currently re-enable a compiled disable (SHIPPED_DISABLED_DETECTORS) — the merge is additive by design.

[lockdown]

[lockdown]
require = true              # refuse to run unless --lockdown is passed

A repo that demands hardened scanning sets this so a plain keyhog scan fails closed instead of silently running unhardened. See the scan --help output for the current --lockdown checks.

[system]

[system]
trusted_bin_dirs = ["/nix/store/example-system-bin/bin"]
cache_dir = "/home/alice/.cache/keyhog"
autoroute_cache = "/home/alice/.cache/keyhog/autoroute.json"
calibration_cache = "/home/alice/.cache/keyhog/calibration.json"
gpu = "auto"
autoroute_gpu = false
batch_pipeline = false

trusted_bin_dirs extends the absolute directory allowlist used for external binaries such as git and docker. This is for Nix/Guix or other non-standard install roots. Relative paths are rejected because the trust boundary must not depend on the process working directory.

cache_dir overrides the Hyperscan compiled-database cache directory. It uses the same precedence as scan flags: compiled platform default, then TOML, then --cache-dir. Relative paths, symlinks, paths outside the user's home or the per-user keyhog temp cache root, and paths owned by another user fail closed.

autoroute_cache overrides the persisted autoroute calibration evidence file. It uses the same precedence as scan flags: compiled platform default, then TOML, then --autoroute-cache. The value must be an absolute file path or off. The cache path is printed by keyhog config --effective; it is storage configuration, not part of the scan identity digest.

calibration_cache opts a scan into per-detector Bayesian confidence calibration written by keyhog calibrate. The scanner never reads the default calibration file implicitly. The value must be an absolute file path in TOML; missing, unreadable, corrupt, or schema-incompatible explicit files fail closed before scanning. The resolved path, entry count, and digest are printed by keyhog config --effective.

gpu resolves GPU init policy. auto leaves GPU available to autoroute and explicit GPU backends, off behaves like --no-gpu, and required behaves like --require-gpu. The resolved value is printed by keyhog config --effective and is part of the autoroute scan identity.

autoroute_gpu controls whether calibration runs may include GPU candidates for eligible workload buckets. It is off by default; installers pass --autoroute-gpu during the visible calibration phase. Normal scans never benchmark from this value; they consume persisted fastest-correct decisions.

batch_pipeline forces the coalesced batch pipeline. Leave it false for the default fused filesystem route; set it only for calibration, diagnostics, or pipeline parity checks. The resolved value is printed by keyhog config --effective and is part of the autoroute scan identity.

[aws]

[aws]
canary_accounts = ["609629065308"]
knockoff_accounts = ["000000000001"]

canary_accounts and knockoff_accounts extend the embedded AWS canary-token issuer baseline used by offline access-key metadata. Each entry must be a 12-digit AWS account ID. Invalid IDs fail closed as configuration errors. Configured accounts are part of the resolved scan config, keyhog config --effective prints their count, and daemon scans route in-process because a running daemon cannot consume client-local [aws] config.

[tuning]

[tuning]
fallback_hs = true
hs_prefilter_max_len = 4096
hs_shard_target = 320
fallback_anchor = true
homoglyph_gate = true
homoglyph_ascii_skip = true
fallback_reverse = false
prefilter_truncate = true
fallback_prefix_gate = false
decode_focus = true
confirmed_suffix_gate = true
no_candidate_gate = true
fallback_localizer = false
gpu_recall_floor = false
gpu_moe_timeout_ms = 30000

These keys tune scanner-internal detection and recall route gates. They are operator-visible resolved config, included in the autoroute config digest, and printed by keyhog config --effective. They do not have CLI flags because per-run hidden recall changes would invalidate installer calibration. hs_shard_target controls Hyperscan patterns-per-shard during compile; changing it affects compile/cache shape and autoroute identity but not detector recall. gpu_recall_floor forces the GPU region-presence path to compute the full CPU trigger net during parity/debug scans and report any GPU under-fire it recovers. gpu_moe_timeout_ms bounds one GPU MoE confidence readback; on timeout KeyHog surfaces the GPU fault and scores the same candidates on CPU MoE.

[allowlist]

file selects the line-based allowlist file (default .keyhogignore at the scan root). require_reason, require_approved_by, and max_expires_days enforce governance before any suppression is active. Missing required metadata, expired entries, malformed entries, or expiry windows beyond the configured limit fail closed with an operator-visible config error. See Suppressions.

Where the numbers live

  • Canonical scan defaults + tuning rationale: crates/core/src/config.rs (ScanConfig::default).
  • Scanner route tuning defaults: crates/scanner/src/scanner_config.rs (ScannerTuningConfig).
  • TOML schema + merge precedence: crates/cli/src/config.rs (ConfigFile, apply_config_file).
  • The resolved struct the live scanner reads (defaults + file + flags folded into one): crates/cli/src/orchestrator_config.rs (resolve_scan_configResolvedScanConfig). Reading this single struct — rather than re-deriving floors from raw args — is what keeps tuned == benched == shipped true on the live path.