KORTHEXDocumentation

Docs / CONFIGURATION

CONFIGURATION

Configuration

Written and maintained by Hendrik Schneider · Last reviewed · How we check this

Korthex is configured through a combination of project-level config files, CLI flags, and environment variables. The project configuration file is korthex.json in the project root; scan caches are written to .korthex_cache/ beside it.

Project Configuration

Run korthex config --init to write the default project configuration to korthex.json in the current directory: { "maxFiles": 100000, "timeoutSeconds": 300, "engines": "", "languages": "", "outputFormat": "krx", "excludeDirs": "node_modules,.git,build,dist,target,bin,obj", "excludeExtensions": ".exe,.dll,.so,.dylib,.bin,.zip,.tar,.gz" } Empty engines and languages mean "all". Validate an edited file with korthex config --validate --strict , which runs the engine validator rather than a plain JSON syntax check. There is no cache block in this file. The scan cache is not configurable from here: it always lives in <project>/.korthex_cache/ and is steered at scan time by the incremental and fullRescan keys of the scanner configuration.

.korthexignore

The .korthexignore file uses gitignore syntax to exclude files and directories from scanning. # Dependencies node_modules/ vendor/ .venv/ # Build outputs dist/ build/ out/ target/ # Test fixtures with intentional weak crypto test/fixtures/legacy-certs/ test/vectors/ # Generated code *.generated.cs *.g.dart Korthex automatically respects .gitignore rules. Use .korthexignore for additional exclusions specific to scanning.

Engine Toggles

Each scan engine can be individually enabled or disabled: # Disable runtime and git-history engines korthex config set engines.runtime false korthex config set engines.gitHistory false

EngineConfig KeyDefault
AST Analysisengines.astenabled
Binary Analysisengines.binaryenabled
Runtime Analysisengines.runtimeenabled
TLS Analysisengines.tlsenabled
Git Historyengines.gitHistoryenabled
Config Analysisengines.configenabled

Detection Toggles

Fine-tune what Korthex detects:

ToggleDescriptionDefault
detection.weakHashesMD5, SHA-1 usage detectionenabled
detection.weakCiphersDES, 3DES, RC4, Blowfishenabled
detection.smallKeysRSA < 2048, ECC < 256enabled
detection.ecbModeECB mode block cipher usageenabled
detection.hardcodedKeysLiteral keys in sourceenabled
detection.expiredCertsCertificate expiration checksenabled
detection.weakTlsTLS 1.0/1.1, weak cipher suitesenabled
detection.pqcReadinessPost-quantum readiness assessmentenabled
detection.insecureRandomMath.random(), rand() for cryptoenabled
detection.nullIvNull/zero initialization vectorsenabled
detection.pkcs1v15PKCS#1 v1.5 padding (Bleichenbacher)enabled
detection.staticSaltHardcoded or missing salt in hashingenabled

Environment Variables

The environment is not a configuration surface here. Two variables are read on the CLI path, and that is the whole list: Nine other variables were documented here and none of them exists. If a pipeline of yours sets KORTHEX_HOME , KORTHEX_LICENSE , KORTHEX_LICENSE_FILE , KORTHEX_LOG_LEVEL , KORTHEX_LOG_LEVEL_<ENGINE> , KORTHEX_LOG_FILE , KORTHEX_NO_TELEMETRY , KORTHEX_PARALLEL or KORTHEX_TIER_OVERRIDE , it has never had an effect. Nothing in the product reads any of them. Verbosity and thread count are configuration keys ( global.logLevel , global.maxThreads ); telemetry is the --no-telemetry flag; licensing goes through the license command.

VariableDescription
KORTHEX_ENGINE_DIRDirectory the CLI loads the engine libraries from, instead of the one it derives from its own install location.
KORTHEX_CI_TOKENThe CI token korthex ci verifies against the backend. Only consulted when it is set.

Policy File Syntax

The policy file is the single place where your organization's algorithm rules, key-size thresholds, deprecation deadlines, and finding-level exemptions live. Korthex supports two interchangeable forms of the same schema: The two are equivalent and either form is accepted by every command that takes a --policy argument. There is no converter command - translate by hand. The .json form is intentionally editable by hand. There is no standalone validator command; the file is checked when a command loads it, and a malformed or unusable policy exits 41 (not 3 - that is the license code). A single missing brace breaks every dependent engine, so exercise a changed policy with korthex policy evaluate --report <file> before you rely on it in CI. Complete example { "schemaVersion": 2, "profile": "balanced", "scanMode": "full", "minimums": { "rsaBits": 2048, "ecBits": 256, "aesBits": 128, "hashBits": 224, "kdfIterations": 600000 }, "deadlines": { "MD5": "2024-12-31", "SHA-1": "2025-12-31", "3DES": "2025-12-31", "RSA": { "below": 2048, "by": "2025-12-31" }, "PQC-migration": "2030-12-31" }, "overrides": [ { "rule": "ECB_MODE_DETECTED", "match": { "file": "tests/fixtures/**" }, "severity": "info", "reason": "Known test fixtures for negative-path tests." }, { "rule": "*", "match": { "file": "vendor/**" }, "action": "ignore", "reason": "Vendor code we do not own." } ], "exemptions": [ { "id": "TKT-9412", "findingFingerprint": "sha256:9c5a3f1b...", "expires": "2026-12-31", "approver": "security-team@acme.com", "reason": "Legacy auth path; scheduled for replacement in Q4." } ], "algorithm-aliases": [ { "wrapper": "com.acme.crypto.SecureHash.compute", "wrapped": "SHA-256", "language": "java" }, { "wrapper-regex": "^acme_legacy_hash_v\\d+$", "wrapped": "MD5", "language": "c" } ], "ciEnforcement": { "mode": "warn-then-block", "failOn": "high", "maxCritical": 0, "maxHigh": 5 } } Profile values Override actions Exemption rules Exemptions must carry an expires date. There is no permanent exemption mechanism by design. The findingFingerprint is a policy-file key. Note that the JSON report emits no fingerprint field, so it cannot be copied out of a report - see Sample Finding JSON . Expired exemptions automatically promote the underlying finding back to its original severity. There is no command that lists active exemptions; read them out of the policy file. Validate & apply # Exercise the policy against a report (this is also the schema check) korthex policy evaluate --report report.krx # Enforce it: exit 1 on violation, 41 if the policy file is unusable korthex policy enforce --report report.krx --fail-on-violation

FileUse for
.kxpEncrypted, canonical form. Loads fastest; tamper-resistant; the form Korthex emits when you export a policy. Recommended for production and CI.
.korthex_policy.jsonPlain-JSON form. Human-readable, editable in any text editor or IDE, version-controllable in plain diffs. Recommended for authoring and review.
ProfilePosture
strictAnything below recommended is a finding. No legacy carve-outs.
balancedAcceptable is fine; deprecated is a finding; legacy carve-outs allowed via exemptions.
legacyOnly disallowed primitives raise findings. For migrating brownfield codebases.
ActionEffect
severity: <level>Re-grade matching findings to a specific severity.
action: ignoreSuppress matching findings entirely.
action: promoteBump matching findings up one severity level.
action: demoteDrop matching findings down one severity level.

Performance Tuning

The two knobs that matter on large repositories are thread count and the delta scan. Both are configuration keys, not CLI flags. Parallelism Thread count is set by global.maxThreads in the scanner configuration. The default, 0 , means "one worker per logical CPU". Lower it on CI runners whose memory budget is smaller than their core count suggests. { "scanPaths": ["."], "global": { "maxThreads": 4 } } Cache Strategy The delta scan is on by default ( incremental: true ). It compares a content hash per file - not a timestamp - re-analyzes the files whose bytes changed plus the transitive hull of everything importing them, and serves the rest from the findings cache. The merged result runs through the same whole-set pipeline as a full scan, so a delta run and a full run of the same tree emit identical artifacts. Engine Toggles for Large Repos Engine selection is a configuration block, not a flag. Disable the engines a given run does not need and pass the file with --config . The canonical shape nests the toggles under subEngines : { "scanPaths": ["."], "engines": { "subEngines": { "gitHistory": false, "binary": false } } } The keys are codeAnalysis , tlsCert , config , gitHistory , runtime , binary , database and exfil . The older flat form, with the toggles directly under engines and no subEngines level, is still read, but each key that arrives that way logs a deprecation warning naming the nested path. Switching every engine off is rejected: the parser requires at least one enabled engine and fails the scan at config validation, before any file is read. Narrowing the walk itself is usually the bigger lever: put shared vendor and build directories into globalFilters.paths.exclude so every engine skips them at once, rather than excluding them per engine. Budgets and Limits These are configuration keys as well. None of them has a command-line switch. There is no memory-ceiling setting, and adding one would not be the lever it sounds like. The scanner regulates its own memory at phase boundaries and gives memory back instead of aborting, precisely because an earlier threshold guard killed healthy runs. To hold peak memory down, narrow the walk and lower global.maxThreads . Profiling a Slow Scan Timing lives in the log, not in the report and not in a flag. Raise global.logLevel and the phases that measure themselves print their durations. Accepted levels are OFF , ERROR , WARN , INFO , DEBUG and TRACE , matched case-insensitively; the default is already INFO , which is the level the timing lines are written at. { "scanPaths": ["."], "global": { "logLevel": "INFO", "maxThreads": 4 } } Be precise about what this gets you, because it is less than a profiler. Six call sites report a duration: the five Context passes (reference resolution, context analysis, neural resolution, taint map, cross-file clusters) and the post-processing enrichment phase. Everything else runs unmeasured. There is no --profile flag, no per-file timing breakdown and no machine-readable timing artifact of any kind: the report carries findings, not durations. If you need per-file numbers today, the honest answer is that Korthex does not produce them. If a single file dominates scan time, it is almost always either auto-generated code, a vendored dependency, or a giant bundle. Adding it to .korthexignore is usually the right answer.

ScenarioRecommendation
First scan on a fresh checkoutNothing to do. There is no snapshot yet, so the run is a full analysis and reports delta_scan_fallback: no-cache while it primes the cache.
CI on an ephemeral runnerNothing to do. Without a preserved .korthex_cache/ every run is cold, and the cache write is what makes the next run cheap if you ever do preserve it.
CI on a persistent runnerPreserve <project>/.korthex_cache/ between builds. That directory is the whole cache; nothing else needs restoring.
Local developmentLeave the default on. Changed files and their importers are re-analyzed; everything else is reused.
Forcing a clean runSet fullRescan: true, which ignores the snapshot and wins over incremental. There is no cache subcommand - to discard the cache instead, delete the .korthex_cache/ directory.
A cache you do not trustYou do not have to guess. A snapshot that is missing, stale, out of scope or corrupt is never trusted partially: the scan silently degrades to a full analysis and names the reason in delta_scan_fallback.
KeyDefaultWhen to set
global.maxThreads0 (one worker per core)Runners that share a machine, or a run you want to keep off the other cores. Bounds how many analyzers hold memory at once.
global.timeoutSeconds0 (no limit)A whole-scan wall-clock budget. Accepted range is 0 to 86400.
codeAnalysis.ast.maxFileSizeBytes4194304 (4 MiB)Files above this are not parsed into a syntax tree. They are still scanned by pattern detection, so raising it buys depth and costs memory, and lowering it does the reverse.
codeAnalysis.ast.parseTimeoutMs2000Per-file parse budget. A generated file that blows past it is abandoned rather than allowed to stall the pass.
codeAnalysis.ast.queryTimeoutMs1000Per-file budget for running the detection queries over an already-parsed tree.