Skip to content

Target Config Reference

Each target has one reviewed source configuration file:

output/<target>/target.toml

Create or refresh it with:

bin/setup-target <target> <repo-url>
bin/setup-target <target>

bin/audit --target <target> also creates this file when it is missing. Runtime values such as RESULTS_DIR and TARGET_REV are written separately to .session-env.

Treat target.toml as generated config plus a small review layer. The tooling infers:

  • source metadata;
  • build system;
  • browser mode from browser-specific build drivers;
  • common ASan executables;
  • common static libraries;
  • default include paths;
  • default sanitizer policy;
  • default threat model controls.

Your job is to edit only values that remain unresolved or are wrong for this target.

At audit preflight this file is copied to output/<target>/<backend>/results/.target.toml. That session snapshot is immutable. Edit the shared file only for a future run; never change the snapshot to retarget probes whose evidence is already being recorded.

Target shape Minimum execution fields to verify
Native CLI is_browser = "0", enabled sanitizer, matching <san>_bin
Native public API Native CLI fields plus <san>_lib, includes, defines, and link_libs as needed
Managed/interpreted runner [sanitizer] enabled = [] plus [runner].bin and args
Go race run [sanitizer] enabled = ["race"] plus a runner command built or invoked with -race
Browser or JS engine is_browser = "1", the product executable, and route-appropriate runner arguments

The config is also part of triage:

  • attacker_controls is read when deciding whether a crash trigger is a legitimate product input.
  • Reproduction export uses the repository URL, revision, build fields, and sanitizer paths to build a clean maintainer bundle.

A complete generic example

target       = "libxml2"
upstream_url = "https://gitlab.gnome.org/GNOME/libxml2.git"
build_system = "cmake"
build_widening = true

asan_bin     = "build-asan/xmllint"
asan_lib     = "build-asan/libxml2.a"
includes     = ["include", "build-asan/include"]
link_libs    = ["-lz", "-llzma", "-lm"]

is_browser   = "0"

[threat_model]
attacker_controls = ["bytes"]

Generated fields to review

Field Meaning
target Target slug. It should match targets/<target> and output/<target>.
upstream_url Source repository URL used as metadata in exported bundles.
build_system Informational build-system label such as cmake, meson, autotools, mach, or gn.
build_widening For ordinary native C/C++ targets, keep the canonical build and prepare one cached ASan sibling with compatible optional in-tree features enabled. Defaults to true when absent on a non-browser native target; set false to opt out.
asan_bin ASan executable used by generic or browser runs. Relative paths resolve under targets/<target>/. An executable in the matching ASan build (or an external executable whose ASan instrumentation can be verified) is kept as you set it; bin/setup-target re-detects this field only to fill it or to replace a missing or mismatched path.
asan_lib ASan library used when compiling C harness testcases.
includes Include directories for C harness builds. Relative paths resolve under targets/<target>/.
link_libs Extra linker inputs for C harness builds: system/library flags such as -lm, target-relative archives, or target-relative source files that must be compiled into the harness. A token containing $ is passed verbatim and never resolved as a path.
is_browser "1" for browser mode, "0" for generic mode.

One related field is not seeded: defines, the compiler define flags for C/C++ harness builds (such as -DFOO=1). Add it by hand when a harness build needs it, or run bin/auto-repair-target-toml to propose it after repeated harness build failures (see Target configuration).

Which fields you need depends on what the run will do:

  • A generic CLI audit needs asan_bin.
  • C harness testcases also need the selected sanitizer's library, includes, defines, and link_libs.
  • ASan uses top-level asan_lib. UBSan, MSan, and TSan harnesses use [sanitizer].ubsan_lib, msan_lib, or tsan_lib.

If only the executable path is correct, a CLI-first audit can still run. Leave the C harness fields unresolved until you actually need public API harnesses.

Header-only libraries

Some C++ libraries ship only headers, with no static archive to link against.

  • Leave asan_lib as the generated FILL_ME comment placeholder, or set it to an empty string.
  • bin/export-repro will emit a reproduce.sh that compiles the harness directly against the target sources without a library link.
  • includes, defines, and link_libs still apply normally.
  • If the harness later starts needing a real archive, replace FILL_ME with the path. The rest of the config does not change.

Optional fields

Field Meaning
cmake_target CMake target name used when a generated bundle can rebuild a specific target.

Build configurations

The canonical build-asan tree is always the regular-configuration control. Build configurations add isolated, content-addressed ASan siblings; they never replace that control or multiply the UBSan, MSan, and TSan build set.

build_widening = true asks TokenFuzz to derive one compatible widened sibling from the working primary recipe. It enables advertised, in-tree optional features while retaining the primary recipe's sanitizer and build contract. If the project exposes no suitable options, no sibling is built and the audit continues on the primary.

Declare configurations only for meaningful mutually exclusive modes that automatic widening cannot combine:

build_widening = true

[[build_config]]
name = "compact"
label = "compact table representation"
flags = ["-DENABLE_COMPACT=ON", "-DTABLE_BITS=8"]
features = ["compact tables"]

name must be a short lowercase identifier. flags are ordered configure arguments: order and duplicates are preserved in the configuration identity. features are human-readable surfaces shown to audit agents. A row uses either non-empty flags or widen = true, not both. Refreshing generated placeholders preserves operator-authored rows.

target.toml is parsed as strict TOML. Invalid section headers or malformed arrays fail fast instead of silently falling back to top-level keys.

Sanitizers

The [sanitizer] section declares which sanitizer runners are intentionally enabled for this target, and where to find each sanitizer's optional suppression file.

Only ASan is enabled by default. The supported sanitizer slugs are asan, ubsan, msan, tsan, and race; everything except asan is opt-in per target. race (Go's runtime race detector) is valid only inside enabled. It routes through [runner] and takes none of the per-sanitizer <name>_bin, <name>_lib, or <name>_suppressions keys below. For when to enable each one and the false-positive trade-offs, see Sanitizer policy.

Findings-only mode (no sanitizer)

For targets that have no sanitizer build, typical for interpreted languages (Python, Ruby, PHP, and so on) or JVM runtimes (Java, Kotlin), set enabled to an explicit empty list:

[sanitizer]
enabled = []

With enabled = []:

  • bin/probe routes testcases through [runner].bin instead of expecting an ASan binary.
  • bin/run-asan generic skips ASAN_OPTIONS injection so the language runtime sees a clean environment.
  • Runtime diagnostics (Python tracebacks, Go panics, Ruby exceptions, Java stack traces, Node fatal errors, Rust panics, and so on) route to findings/ instead of being published as sanitizer crashes. Genuine sanitizer-class memory-safety signals (ASan, TSan, MSan, Go race detector) still stay in crashes/.

When [sanitizer] is absent entirely from target.toml, the default, ["asan"], applies. Only an explicit empty list opts the target out.

Per-sanitizer keys

Key Meaning
enabled List of sanitizer slugs intentionally enabled for this target. Defaults to ["asan"].
<name>_suppressions Path to a suppression file. Appended via <NAME>_OPTIONS=suppressions=… at runner startup. Missing files emit a warning but do not abort.
<name>_options Additional colon-separated runtime options appended to <NAME>_OPTIONS.
ubsan_bin / msan_bin / tsan_bin Per-sanitizer binary overrides for opt-in runners. asan_bin is the top-level ASan binary field.
ubsan_lib / msan_lib / tsan_lib Optional per-sanitizer library used when compiling C/C++ HARNESS: testcases. ASan uses top-level asan_lib.

Example

asan_bin = "build-asan/xmllint"

[sanitizer]
enabled = ["asan", "msan"]
asan_suppressions  = "build-asan/asan-suppressions.txt"
msan_suppressions  = "build-msan/msan-suppressions.txt"
msan_bin           = "build-msan/xmllint"
msan_lib           = "build-msan/libxml2.a"

UBSan and TSan follow the same shape: add the slug to enabled and set the matching <name>_bin, <name>_lib, and <name>_suppressions keys.

Notes:

  • Paths are relative to targets/<target>/ unless absolute.
  • Relative paths whose first segment is build-asan, build-ubsan, build-msan, or build-tsan are AUDIT_BUILD_SUFFIX-aware. Inside bin/audit-container-shell, those paths resolve to the per-image suffixed build directory; outside the container the suffix is empty.
  • Unknown sanitizer slugs in enabled are logged on stderr and dropped. The loader falls back to ["asan"] if [sanitizer] was absent and nothing valid remains.
  • An explicit empty list (enabled = []) is honoured as findings-only mode and is not re-defaulted to ["asan"].
  • Runner scripts warn when invoked for a sanitizer that is not listed in enabled but do not abort. That keeps one-off reproduction and debugging commands usable.

Language runner

The [runner] section is the language-agnostic invocation contract. It is used by bin/probe and bin/run-asan generic whenever no sanitizer binary is configured: most commonly when [sanitizer] enabled = [], but also for compiled-language targets that want to plug in a custom driver script.

Key Meaning
bin Interpreter or driver program (python3, node, cargo, ruby, an absolute path to a wrapper script, and so on). A bare name is resolved on PATH first, then as a path relative to targets/<target>/, which is how a config points at a binary the target's own build produced. It runs with targets/<target>/ as its working directory, so a language whose dependency resolver reads the current directory (Go modules, for one) finds the audited package; testcase paths reach it absolute.
args Literal argument list, with the runner tokens below substituted at run time.
env Extra KEY=VAL strings layered on the runtime environment (for example ["GORACE=halt_on_error=1"] or ["PYTHONDEVMODE=1"]). The same tokens are substituted.
crash_patterns Additional regex strings the triager treats as crash signals beyond its built-in language-agnostic markers. Use sparingly.
success_codes Process exit codes from 0 through 123 that mean the runner completed normally. Defaults to [0]. bin/setup-target records the exit observed while validating the configured input route, accepting a nonzero code only after review confirms malformed-input rejection rather than startup or argv failure. 124 and above is where the timeout wrapper's own status, exec failures, and signal deaths live, so it is never accepted. A run whose output carries a sanitizer diagnostic is classified as a crash before its exit code is read, and calibration refuses an exit observed with one. The set describes the configured program only; an agent-built harness keeps 0 as its only success.

Before model preflight or benchmark cells start, bin/audit and bin/benchmark resolve any configured bin and verify that it is executable. Standard language runners are also invoked with their version command, so an installed launcher with a missing runtime (a java stub with no JDK, say) fails immediately rather than burning model budget. bin is optional: a findings-only target with no runner audits in code-review mode (testcase execution is disabled, and probes report that); only a configured runner that is unusable is a fatal startup error.

Runner tokens

Token Expands to
{TESTCASE} Path to the testcase being run.
{TARGET_ROOT} targets/<target>/.
{RESULTS_DIR} This session's results/ directory.
{TARGET_SLUG} The target slug.
{SANITIZER} The selected sanitizer slug (asan, ubsan, …).
{SWIFT_SANITIZER} The Swift spelling of that slug: address, undefined, or thread. Any other sanitizer is a hard error, not a silent empty value.
{NULL_DEVICE} The platform's null device (/dev/null).
{PROFILE} A fresh temporary browser profile. Valid only in browser execution; elsewhere it is an error.

{TESTCASE} has one extra rule:

  • When {TESTCASE} appears in args, it is replaced in place and the runner does not also append the testcase path.
  • When {TESTCASE} is absent, the runner adds the testcase path after the expanded args, in the conventional last position.

Examples

# Pure Python target: interpreter + dev-mode env.
[runner]
bin            = "python3"
args           = ["{TESTCASE}"]
env            = [
  "PYTHONDEVMODE=1",
  "PYTHONPATH={TARGET_ROOT}:{TARGET_ROOT}/src:{TARGET_ROOT}/lib",
]
crash_patterns = []
# Go target: findings-only driver via `go run`.
[runner]
bin            = "go"
args           = ["run", "{TESTCASE}"]
env            = ["GORACE=halt_on_error=1"]
crash_patterns = []

To enable the Go runtime race detector, set [sanitizer] enabled = ["race"] and use args = ["run", "-race", "{TESTCASE}"].

# Rust target: cargo run with the testcase path as an argument.
[runner]
bin            = "cargo"
args           = ["run", "--quiet", "--manifest-path", "{TARGET_ROOT}/Cargo.toml", "--", "{TESTCASE}"]
env            = []
crash_patterns = []
# Swift package: the runner compiles with the selected Swift sanitizer
# (`address`, `undefined`, or `thread`). The argument before `{TESTCASE}`
# names the executable product to run, and is what audit preflight builds;
# replace `{TARGET_SLUG}` with the product's own name whenever the two
# differ, which they always do under a nested slug.
[runner]
bin            = "swift"
args           = ["run", "--quiet", "--disable-sandbox", "--skip-build", "-c", "release", "-Xswiftc", "-sanitize={SWIFT_SANITIZER}", "-Xswiftc", "-O", "--scratch-path", "{TARGET_ROOT}/.audit/swift-build-{SWIFT_SANITIZER}", "--package-path", "{TARGET_ROOT}", "{TARGET_SLUG}", "{TESTCASE}"]
env            = []
crash_patterns = []
# Custom wrapper script: useful for Java/Kotlin builds that need a classpath
# or a wrapper that pre-configures JNI agents.
[runner]
bin            = "./tools/run-testcase.sh"
args           = ["{TESTCASE}"]
env            = []
crash_patterns = ['^DEFENSIVE-ASSERT-FAILED:']

bin/setup-target emits a starter [runner] block driven by the detected build system. The seeded values are commented when the build system is unknown so the file is safe to parse before the operator fills it in.

Threat model

attacker_controls describes what an external caller can legitimately control. Triage compares crash report Trigger source values against this list, then lets the source reviewer correct that comparison from the code. A settled review is reportable only when every required trigger component is in the list: crafted bytes deciding the fault is not enough when the fault also needs an application call order the list does not cover. A defect the reviewer confirms is outside the list is rejected with a threat-model: reason, its evidence kept under the rejected tree; one the reviews cannot settle after the focused resolution is rejected as unsettled rather than left without a verdict.

Token Meaning
bytes Caller-controlled bytes: file, stream, packet, archive, media, regex, or similar data.
call-sequence Ordered public API, script, plugin, or Web API calls.
timing Event-loop scheduling, GC timing, JIT tier-up, or similar timing.
race Thread or process interleaving.
protocol-state Multi-message protocol state.
env Process environment variables.
fs-state Filesystem paths, presence, permissions, or layout.

Unknown tokens are logged on stderr and ignored; if the resulting list is empty, the loader defaults to ["bytes"]. The synonym call-order is normalised to call-sequence.

Examples:

[threat_model]
attacker_controls = ["bytes"]
[threat_model]
attacker_controls = ["bytes", "call-sequence", "timing"]
[threat_model]
attacker_controls = ["bytes", "call-sequence", "protocol-state"]

Browser mode

Generic targets:

is_browser = "0"

Browser or browser-like runtime targets:

is_browser = "1"

Browser mode enables:

  • browser and JS testcase assumptions;
  • coverage-gated browser or shell runs when available.

The browser binary and launch arguments are target metadata. For example:

asan_bin = "build-asan/MyBrowser.app/Contents/MacOS/MyBrowser"

[runner]
args = ["--user-data-dir={PROFILE}", "--headless=new", "--dump-dom", "{TESTCASE}"]

{PROFILE} expands to a fresh temporary profile directory for each browser probe. bin/setup-target seeds launch arguments for structurally detected browser build drivers; other browsers set them explicitly.

Session environment

At audit startup, bin/audit writes the active session file:

output/<target>/<backend>/results/.session-env

It contains dynamic values:

  • RESULTS_DIR;
  • TARGET_ROOT;
  • TARGET_SLUG;
  • TARGET_REV;
  • TARGET_REPO_TYPE;
  • LOGDIR;
  • SESSION_STARTED;
  • TARGET_CONFIG_SHA256.

bin/probe discovers the nearest .session-env by walking upward from the testcase path and current directory. Scratch testcases under results/ therefore do not need manual environment setup.

After preflight, bin/audit copies the target configuration to output/<target>/<backend>/results/.target.toml and records its digest as TARGET_CONFIG_SHA256. Every config consumer in that session (probes, sanitizer runners, severity, report enrichment) reads the snapshot, so an edit to the shared output/<target>/target.toml applies to the next run rather than retargeting probes already contributing to this one. Editing or removing the snapshot itself is a contract violation and fails loudly.

Strategy hints: [s6_peers]

[s6_peers] lists upstream peer projects to mine for S6 (cross-project variant):

[s6_peers]
domain = "xml-parser"
peers  = ["libexpat", "Xerces-C++", "rapidxml"]

Empty or missing values are fine. The section only suggests additional strategy material. bin/setup-target can also LLM-bootstrap a real [threat_model] and [s6_peers] instead of the conservative defaults; you can re-run that derivation at any time:

bin/suggest-threat-model <slug> --apply --force   # re-derive attacker_controls
bin/suggest-peers <slug> --apply --force          # re-derive [s6_peers]

bin/setup-target accepts --no-llm-config to keep the deterministic seed and skip LLM enrichment. Use it when setup must stay offline; otherwise let the suggestions run and review them.

The audited revision

target.toml records no revision. A revision written once at setup goes stale the moment the checkout advances, and a stale commit in an exported bundle or a report source link is a wrong answer that reads like a right one.

At audit startup the live source revision is written to .session-env as TARGET_REV, which is exact for that run. Reports and exported bundles use it, falling back to the checkout's own current revision when no session recorded one.