Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Configuration

Nyx uses TOML configuration files. A default config is auto-generated on first run. If you’d rather edit settings and rules from the browser, the Config page in nyx serve is a live editor that writes back to nyx.local:

Nyx config page: General settings, Triage Sync toggle, Sources panel with language/matcher/capability dropdowns and a per-language matcher table

File Locations

PlatformDirectory
Linux~/.config/nyx/
macOS~/Library/Application Support/nyx/
Windows%APPDATA%\elicpeter\nyx\config\

Run nyx config path to see the exact directory on your system.

File Precedence

  1. nyx.conf – Default config (auto-created from built-in template on first run)
  2. nyx.local – User overrides (loaded on top of defaults)

Both files are optional. CLI flags take precedence over both.

Merge Strategy

TypeBehavior
Scalars (mode, min_severity, booleans)User value wins
Arrays (excluded_extensions, excluded_directories, excluded_files)Union + deduplicate
Analysis rulesPer-language union with deduplication
ProfilesUser profile with same name fully replaces built-in
Server / RunsUser value wins (full section override)

Example:

# nyx.conf (default):
excluded_extensions = ["jpg", "png", "exe"]

# nyx.local (user):
excluded_extensions = ["foo", "jpg"]

# Effective result:
# ["exe", "foo", "jpg", "png"]  -- sorted, deduped union

Full Schema

[scanner]

FieldTypeDefaultDescription
mode"full" | "ast" | "cfg" | "taint""full"Analysis mode
min_severity"Low" | "Medium" | "High""Low"Minimum severity to report
max_file_size_mbint | null16Max file size in MiB; null = unlimited. Default is a safe ceiling for untrusted repos; lift explicitly when scanning trusted codebases with large generated files
excluded_extensions[string]["jpg", "png", "gif", "mp4", ...]File extensions to skip
excluded_directories[string]["node_modules", ".git", "target", ...]Directories to skip
excluded_files[string][]Specific files to skip
read_global_ignoreboolfalseHonor global ignore file (RESERVED)
read_vcsignorebooltrueHonor .gitignore / .hgignore
require_git_to_read_vcsignorebooltrueRequire .git dir to apply gitignore
one_file_systemboolfalseDon’t cross filesystem boundaries
follow_symlinksboolfalseFollow symbolic links
scan_hidden_filesboolfalseScan dot-files
include_nonprodboolfalseKeep original severity for test/vendor paths
enable_state_analysisbooltrueEnable resource lifecycle + auth state analysis. Detects use-after-close, double-close, resource leaks (per-function scope), and unauthenticated access. Requires mode = "full" or mode = "taint".

[database]

FieldTypeDefaultDescription
pathstring""Custom SQLite DB path; empty = platform default (RESERVED)
auto_cleanup_daysint30Days to keep DB files (RESERVED)
max_db_size_mbint1024Maximum DB size in MiB (RESERVED)
vacuum_on_startupboolfalseRun VACUUM before indexed scans

[output]

FieldTypeDefaultDescription
default_format"console" | "json" | "sarif""console"Default output format (used when --format is not specified)
quietboolfalseSuppress status messages
max_resultsint | nullnullCap number of findings; null = unlimited
attack_surface_rankingbooltrueEnable attack-surface ranking
min_scoreint | nullnullMinimum rank score to include; null = no minimum
min_confidencestring | nullnullMinimum confidence level ("low", "medium", "high"); null = no minimum
include_qualityboolfalseInclude Quality-category findings (hidden by default)
show_allboolfalseDisable category filtering, rollups, and LOW budgets
max_lowint20Maximum total LOW findings to show (rollups count as 1)
max_low_per_fileint1Maximum LOW findings per file (rollups count as 1)
max_low_per_ruleint10Maximum LOW findings per rule (rollups count as 1)
rollup_examplesint5Number of example locations stored in rollup findings

[performance]

FieldTypeDefaultDescription
max_depthint | nullnullMax filesystem traversal depth; null = unlimited
min_depthint | nullnullMin depth for reported entries (RESERVED)
pruneboolfalseStop traversing into matching directories (RESERVED)
worker_threadsint | nullnullWorker thread count; null/0 = auto-detect
batch_sizeint100Files per index batch
channel_multiplierint4Channel capacity = threads x multiplier
rayon_thread_stack_sizeint8388608Rayon thread stack size in bytes (8 MiB)
scan_timeout_secsint | nullnullPer-file timeout in seconds (RESERVED)
memory_limit_mbint512Max memory in MiB (RESERVED)

[server]

Configuration for the local web UI (nyx serve).

FieldTypeDefaultDescription
enabledbooltrueWhether the serve command is enabled
hoststring"127.0.0.1"Host to bind to (localhost by default)
portint9700Port for the web UI
open_browserbooltrueOpen browser automatically on serve
auto_reloadbooltrueAuto-reload UI when scan results change
persist_runsbooltruePersist scan runs for history view
max_saved_runsint50Maximum number of saved runs

[runs]

Configuration for scan run persistence and history.

FieldTypeDefaultDescription
persistboolfalsePersist scan run history to disk
max_runsint100Maximum number of runs to keep
save_logsboolfalseSave scan logs with each run
save_stdoutboolfalseSave stdout capture with each run
save_code_snippetsbooltrueSave code snippets in findings

[profiles.<name>]

Named scan presets that override scan-related config. Activate with --profile <name>.

All fields are optional; omitted fields inherit from the base config.

FieldTypeDescription
modestringAnalysis mode
min_severitystringMinimum severity
max_file_size_mbintMax file size in MiB
include_nonprodboolKeep original severity for test/vendor
enable_state_analysisboolEnable state analysis
default_formatstringOutput format
quietboolSuppress status output
attack_surface_rankingboolEnable ranking
max_resultsintMax findings
min_scoreintMin rank score
show_allboolShow all findings
include_qualityboolInclude quality findings
worker_threadsintWorker thread count
max_depthintMax traversal depth

Built-in profiles:

NameDescription
quickAST-only, medium+ severity
fullFull analysis with state analysis enabled
ciFull analysis, medium+ severity, quiet, SARIF output
taint_onlyTaint analysis only
conservative_large_repoAST-only, high severity, 5 MiB file limit, depth 10

User-defined profiles with the same name as a built-in will override it.

[analysis.engine]

Release-grade switches for the optional analysis passes. Each toggle has a matching CLI flag (pair of --foo / --no-foo) that overrides the config value for a single run. These used to be NYX_* environment variables (NYX_CONSTRAINT, NYX_ABSTRACT_INTERP, NYX_SYMEX, NYX_CROSS_FILE_SYMEX, NYX_SYMEX_INTERPROC, NYX_CONTEXT_SENSITIVE, NYX_PARSE_TIMEOUT_MS, NYX_SMT); those env vars are still honored as a last-resort override when nyx is used as a library (no CLI entry point), but the config/CLI surface is the stable path.

FieldTypeDefaultDescription
constraint_solvingbooltruePath-constraint solving (prunes infeasible paths in taint)
abstract_interpretationbooltrueInterval / string / bit abstract domains carried through the SSA worklist
context_sensitivebooltruek=1 context-sensitive callee inlining for intra-file calls
backwards_analysisboolfalseDemand-driven backwards taint walk from sinks (adds scan time; default off)
parse_timeout_msint10000Per-file tree-sitter parse timeout; 0 disables the cap

[analysis.engine.symex] sub-section:

FieldTypeDefaultDescription
enabledbooltrueRun the symex pipeline after taint; adds witness strings and symbolic verdicts
cross_filebooltruePersist / consult cross-file SSA bodies so symex can reason about callees defined in other files
interproceduralbooltrueIntra-file interprocedural symex (k ≥ 2 via frame stack)
smtbooltrueUse the SMT backend when nyx is built with the smt feature; ignored otherwise

CLI flag map (each pair is --enable / --no-enable):

Config fieldCLI flags
constraint_solving--constraint-solving / --no-constraint-solving
abstract_interpretation--abstract-interp / --no-abstract-interp
context_sensitive--context-sensitive / --no-context-sensitive
backwards_analysis--backwards-analysis / --no-backwards-analysis
parse_timeout_ms--parse-timeout-ms <N>
symex.enabled--symex / --no-symex
symex.cross_file--cross-file-symex / --no-cross-file-symex
symex.interprocedural--symex-interproc / --no-symex-interproc
symex.smt--smt / --no-smt

Engine-depth profile shortcut: instead of flipping individual toggles, pass --engine-profile {fast,balanced,deep} to set the whole stack at once. Individual flags override the profile, so --engine-profile fast --backwards-analysis runs the fast stack with backwards analysis on. See docs/cli.md for the exact toggle matrix.

Explain effective engine: pass --explain-engine to print the resolved engine configuration (profile + config + CLI overrides) and exit without scanning.

[analysis.languages.<slug>]

Per-language custom rules. <slug> is one of: rust, javascript, typescript, python, go, java, c, cpp, php, ruby.

FieldTypeDescription
rulesarray of rule objectsCustom label rules
terminators[string]Functions that terminate execution
event_handlers[string]Event handler function names

Rule object:

[[analysis.languages.javascript.rules]]
matchers = ["escapeHtml"]
kind = "sanitizer"        # "source" | "sanitizer" | "sink"
cap = "html_escape"       # "env_var" | "html_escape" | "shell_escape" |
                          # "url_encode" | "json_parse" | "file_io" |
                          # "fmt_string" | "sql_query" | "deserialize" |
                          # "ssrf" | "code_exec" | "crypto" | "all"

Example Configurations

Minimal override (nyx.local)

[scanner]
min_severity = "Medium"

[output]
default_format = "json"
max_results = 100

CI-optimized

[scanner]
mode = "full"
min_severity = "Medium"
excluded_directories = ["node_modules", ".git", "target", "vendor", "dist"]

[output]
quiet = true
default_format = "sarif"

[performance]
worker_threads = 4

Using a scan profile

# Use a built-in profile
nyx scan --profile ci

# CLI flags still override profile values
nyx scan --profile ci --format json

Custom profile

[profiles.security_audit]
mode = "full"
min_severity = "Low"
enable_state_analysis = true
show_all = true

Custom rules for a Node.js project

[analysis.languages.javascript]
terminators = ["process.exit", "abort"]
event_handlers = ["addEventListener"]

[[analysis.languages.javascript.rules]]
matchers = ["escapeHtml", "sanitizeInput"]
kind = "sanitizer"
cap = "html_escape"

[[analysis.languages.javascript.rules]]
matchers = ["dangerouslySetInnerHTML"]
kind = "sink"
cap = "html_escape"

[[analysis.languages.javascript.rules]]
matchers = ["getRequestBody", "readUserInput"]
kind = "source"
cap = "all"

Adding rules via CLI

# Add a sanitizer
nyx config add-rule --lang javascript --matcher escapeHtml --kind sanitizer --cap html_escape

# Add a terminator
nyx config add-terminator --lang javascript --name process.exit

# Verify
nyx config show

Config Validation

Config is validated after loading and merging. Validation checks include:

  • Server port must be 1–65535
  • Server host must not be empty
  • max_saved_runs must be > 0 when persist_runs is true
  • max_runs must be > 0 when persist is true
  • batch_size and channel_multiplier must be > 0
  • rollup_examples must be > 0
  • Profile names must be alphanumeric with underscores only

Invalid config produces structured error messages identifying the section, field, and issue.


State Analysis

State analysis detects resource lifecycle violations (use-after-close, double-close, resource leaks) and unauthenticated access patterns. It is enabled by default.

To disable:

[scanner]
enable_state_analysis = false

State analysis requires mode = "full" or mode = "taint". It has no effect in mode = "ast".

Tradeoffs:

  • Additional per-function state-machine pass adds some scan time
  • May produce findings that require domain knowledge to evaluate (e.g., whether a resource handle is intentionally left open)
  • Most useful for C, C++, Rust, Go, and Java where acquire/release patterns are common

Upgrading

Engine-version mismatch is handled automatically

Nyx stores the scanner’s CARGO_PKG_VERSION in the project index database. When the version recorded in the DB differs from the running binary; or the row is missing entirely; every cached summary, SSA body, and file-hash row is wiped on the next open so the next scan rebuilds the index against the new engine. No flag is needed; CI pipelines keep working across upgrades.

The rebuild is logged at info level:

engine version changed (0.4.0 → 0.5.0), rebuilding index

If you see this once per upgrade it is working as intended. If you see it on every scan, the metadata row is not being persisted; file an issue.

Forcing a reindex

Use --index rebuild to throw away the current project’s cached summaries and re-run pass 1 against the current rules. Useful after editing nyx.local rules, after an upgrade that changed label definitions without changing the engine version, or when you want a known-clean baseline:

nyx scan --index rebuild .

This clears the current project’s rows in files, function_summaries, ssa_function_summaries, and ssa_function_bodies; other projects sharing the same DB directory are untouched.

Recovering from a corrupt database

If the .sqlite file itself is damaged (e.g. from a killed scan or full disk) and nyx scan fails to open it, delete the file and let the next scan recreate it:

rm "$(nyx config path)"/<project>.sqlite*

On the next scan Nyx builds a fresh index from scratch.


Reserved Fields

Some config fields are defined but not yet implemented. They are marked (RESERVED) in the default config and accept values without effect. This allows forward-compatible config files; settings will activate when the feature is implemented without requiring config changes.