Nyx is a lightweight, lightning-fast Rust-native command-line tool that detects security vulnerabilities across 10 programming languages. It combines tree-sitter parsing, intra-procedural control-flow graphs, and cross-file taint analysis with an optional SQLite-backed index to deliver deep, repeatable scans on projects of any size.
| Capability | Description |
|---|---|
| Multi-language support | Rust, C, C++, Java, Go, PHP, Python, Ruby, TypeScript, JavaScript |
| AST-level pattern matching | Language-specific queries written against precise parse trees |
| Control-flow graph analysis | Auth gaps, unguarded sinks, unreachable security code, resource leaks, error fallthrough |
| Cross-file taint tracking | Monotone forward dataflow taint analysis from sources through sanitizers to sinks with function summaries |
| Cross-language interop | Taint flows across language boundaries via explicit interop edges |
| Two-pass architecture | Pass 1 extracts function summaries; Pass 2 runs taint with full cross-file context |
| Incremental indexing | SQLite database stores file hashes, summaries, and findings to skip unchanged files |
| Parallel execution | File walking and analysis run concurrently via Rayon; scales with available CPU cores |
| Configurable analysis rules | Define custom sources, sanitizers, sinks, terminators, and event handlers per language via TOML config or CLI |
| Configurable scan parameters | Exclude directories, set maximum file size, tune worker threads, limit output, and more |
| Multiple output formats | Console (default), JSON, and SARIF 2.1.0 for CI integration |
| Progress reporting | Real-time progress bars for file discovery and analysis passes |
| Advantage | What it means for you |
|---|---|
| Pure-Rust, single binary | No JVM, Python, or server to install; drop the nyx executable into your $PATH and go. |
| Massively parallel | Uses Rayon and a thread-pool walker; scales to all CPU cores. Scanning the entire rust-lang/rust codebase (~53,000 files) on an M2 MacBook Pro takes ~1 s. |
| Deep analysis | Real CFG construction and monotone dataflow taint analysis with guaranteed termination, not just regex matching. Cross-file function summaries, capability-based sanitizer tracking, and scored findings. |
| Index-aware | An optional SQLite index stores file hashes and findings; subsequent scans touch only changed files, slashing CI times. |
| Offline & privacy-friendly | Requires no login, cloud account, or telemetry. Perfect for air-gapped environments and strict compliance policies. |
| Tree-sitter precision | Parses real language grammars, not regexes, giving far fewer false positives than line-based scanners. |
| Extensible | Add new patterns with concise tree-sitter queries; no SaaS lock-in. |
$ cargo install nyx-scanner-
Navigate to the Releases page of the repository.
-
Download the appropriate binary for your system:
nyx-x86_64-unknown-linux-gnu.zipfor Linuxnyx-x86_64-pc-windows-msvc.zipfor Windowsnyx-x86_64-apple-darwin.zipornyx-aarch64-apple-darwin.zipfor macOS (Intel or Apple Silicon) -
Unzip the file and move the executable to a directory in your system PATH:
# Example for Unix systems unzip nyx-x86_64-unknown-linux-gnu.zip chmod +x nyx sudo mv nyx /usr/local/bin/# Example for Windows in PowerShell Expand-Archive -Path nyx-x86_64-pc-windows-msvc.zip -DestinationPath . Move-Item -Path .\nyx.exe -Destination "C:\Program Files\Nyx\" # Add to PATH manually if needed
-
Verify the installation:
nyx --version
$ git clone https://github.com/elicpeter/nyx.git
$ cd nyx
$ cargo build --release
# optional – copy the binary into PATH
$ cargo install --path .Nyx targets stable Rust 1.85 or later.
# Scan the current directory (creates/uses an index automatically)
$ nyx scan
# Scan a specific path and emit JSON
$ nyx scan ./server --format json
# Emit SARIF 2.1.0 for CI integration (GitHub Code Scanning, etc.)
$ nyx scan --format sarif > results.sarif
# Perform an ad-hoc scan without touching the index
$ nyx scan --index off
# Restrict results to high-severity findings
$ nyx scan --severity HIGH
# Filter by severity expression (high and medium)
$ nyx scan --severity ">=MEDIUM"
# AST pattern matching only (fastest, no CFG/taint)
$ nyx scan --mode ast
# CFG + taint analysis only (skip AST pattern rules)
$ nyx scan --mode cfg
# CI gate: fail on medium+, SARIF output
$ nyx scan --format sarif --fail-on MEDIUM > results.sarif
# Suppress status messages (for CI/scripting)
$ nyx scan --quiet --format json
# Include test/vendor/benchmark paths at original severity
# (by default these are downgraded one tier)
$ nyx scan --keep-nonprod-severity# Create or rebuild an index
$ nyx index build [PATH] [--force]
# Display index metadata (size, modified date, etc.)
$ nyx index status [PATH]
# List all indexed projects (add -v for detailed view)
$ nyx list [-v]
# Remove a single project or purge all indexes
$ nyx clean <PROJECT_NAME>
$ nyx clean --all# Print the effective merged configuration
$ nyx config show
# Print the config directory path
$ nyx config path
# Add a custom sanitizer rule (written to nyx.local)
$ nyx config add-rule --lang javascript --matcher escapeHtml --kind sanitizer --cap html_escape
# Add a terminator function
$ nyx config add-terminator --lang javascript --name process.exitNyx supports four analysis modes, selectable via --mode or the scanner.mode config option:
| Mode | CLI flag | What runs |
|---|---|---|
| Full (default) | --mode full |
AST pattern matching + CFG construction + taint analysis |
| AST-only | --mode ast |
AST pattern matching only; skips CFG and taint entirely |
| CFG | --mode cfg |
CFG + taint analysis only; filters out AST pattern findings |
| Taint | --mode taint |
Alias for cfg (CFG + taint analysis) |
| Finding | Rule ID | Description |
|---|---|---|
| Tainted data flow | taint-* |
Untrusted data (env vars, user input, file reads) flowing to dangerous sinks (shell exec, SQL, file write) without matching sanitization |
| Unguarded sink | cfg-unguarded-sink |
Sink calls not dominated by a guard or sanitizer on the control-flow path |
| Auth gap | cfg-auth-gap |
Web handler functions that reach privileged sinks without an auth check |
| Unreachable security code | cfg-unreachable-* |
Sanitizers, guards, or sinks in dead code branches |
| Error fallthrough | cfg-error-fallthrough |
Error-handling branches that don't terminate, allowing execution to fall through to dangerous operations |
| Resource leak | cfg-resource-leak |
Resources acquired but not released on all exit paths (malloc/free, fopen/fclose, Lock/Unlock) |
| Use-after-close | state-use-after-close |
Variable read/written after its resource handle was closed |
| Double-close | state-double-close |
Resource handle closed more than once |
| Must-leak | state-resource-leak |
Resource acquired but never closed on any exit path |
| May-leak | state-resource-leak-possible |
Resource open on some but not all exit paths |
| Unauthenticated access | state-unauthed-access |
Sensitive sink reached without a preceding auth/admin check |
Every finding is assigned a deterministic attack-surface score that estimates exploitability using only information already in memory — no extra source passes are needed. Findings are sorted by descending score before truncation, so max_results always keeps the most important results.
The score is the sum of five components:
| Component | Weight | Description |
|---|---|---|
| Severity base | High = 60, Medium = 30, Low = 10 | Primary ordering signal. Severity reflects source-kind exploitability and rule confidence. |
| Analysis kind | taint = +10, state = +8, cfg = +3/+5, ast = 0 | Taint-confirmed flows are the strongest signal; AST-only pattern matches rank lowest at equal severity. CFG findings with evidence get +5, without get +3. |
| Evidence strength | +1 per evidence item (max 4), +2–6 for source kind | More evidence increases confidence. Source-kind priority: user input (+6) > env/config (+5) > unknown (+4) > file system (+3) > database (+2). |
| State rule type | +1 to +6 | Use-after-close and unauthenticated access (+6) rank above double-close (+3), must-leak (+2), and may-leak (+1). |
| Path validation | −5 | Findings on paths guarded by a validation predicate receive a small exploitability penalty — the guard may prevent triggering. |
Score ranges (approximate):
| Finding type | Score |
|---|---|
| High taint + user input | ~78 |
| High state (use-after-close) | ~74 |
| High CFG structural | ~63 |
| Medium taint + env source | ~47 |
| Medium state (resource leak) | ~40 |
| Low AST-only pattern | ~10 |
Tie-breaking is deterministic: severity → rule ID → file path → line → column → message hash. The same set of findings always produces the same ordering regardless of parallelism or input order.
Ranking is enabled by default. Disable it with --no-rank or output.attack_surface_ranking = false in config. When disabled, rank_score is omitted from JSON/SARIF output.
All 10 languages have full AST pattern matching and CFG/taint analysis. Resource leak detection is available where language-specific acquire/release pairs are defined.
| Language | AST Patterns | CFG + Taint | Resource Leaks |
|---|---|---|---|
| Rust | Yes | Yes | Yes |
| C | Yes | Yes | Yes |
| C++ | Yes | Yes | Yes |
| Java | Yes | Yes | Yes |
| Go | Yes | Yes | Yes |
| PHP | Yes | Yes | Yes |
| Python | Yes | Yes | Yes |
| Ruby | Yes | Yes | Yes |
| TypeScript | Yes | Yes | Yes |
| JavaScript | Yes | Yes | Yes |
Nyx merges a default configuration file (nyx.conf) with user overrides (nyx.local). Both live in the platform-specific configuration directory shown below.
| Platform | Directory |
|---|---|
| Linux | ~/.config/nyx/ |
| macOS | ~/Library/Application Support/nyx/ |
| Windows | %APPDATA%\elicpeter\nyx\config\ |
Minimal example (nyx.local):
[scanner]
mode = "full" # full | ast | taint
min_severity = "Medium"
follow_symlinks = true
excluded_extensions = ["mp3", "mp4"]
[output]
default_format = "json"
max_results = 200
quiet = true # suppress status messages
[performance]
worker_threads = 8 # 0 = auto-detect
batch_size = 200
channel_multiplier = 2You can define custom sources, sanitizers, sinks, terminators, and event handlers per language. These take priority over built-in rules, letting you teach Nyx about project-specific functions.
[analysis.languages.javascript]
terminators = ["process.exit"]
event_handlers = ["addEventListener"]
[[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" | "all"
[[analysis.languages.javascript.rules]]
matchers = ["dangerouslySetHTML"]
kind = "sink"
cap = "html_escape"Rules can also be added interactively via nyx config add-rule and nyx config add-terminator.
A fully documented nyx.conf is generated automatically on first run.
Nyx uses a two-pass architecture to enable cross-file analysis without sacrificing parallelism:
- File enumeration -- A parallel walker (Rayon +
ignorecrate) applies gitignore rules, size limits, and user exclusions. - Pass 1 -- Summary extraction -- Each file is parsed via tree-sitter, an intra-procedural CFG is built (petgraph), and a
FuncSummaryis exported per function capturing source/sanitizer/sink capabilities (bitflags), taint propagation behavior, and callee lists. Summaries are persisted to SQLite. - Summary merge -- All per-file summaries are merged into a
GlobalSummariesmap with conservative conflict resolution (union caps, OR booleans). - Pass 2 -- Analysis -- Files are re-parsed and analyzed with the full cross-file context: a monotone forward dataflow engine resolves callees against local and global summaries and propagates taint through a bounded lattice with guaranteed convergence. CFG analysis checks for auth gaps, unguarded sinks, resource leaks, and more.
- Reporting -- Findings are scored, ranked, deduplicated, and emitted to the console or serialized as JSON.
With indexing enabled, Pass 1 skips files whose blake3 content hash is unchanged, and cached findings are served directly for AST-only results.
| Feature | Status | Description |
|---|---|---|
| Interprocedural call graph | Done | Precise symbol resolution via FuncKey, language-scoped namespaces, cross-module linking. Full call graph with SCC and topological analysis. |
| Path-sensitive analysis | Done | Track path predicates and conditional constraints. Detect infeasible paths and validation-only-in-one-branch patterns. Monotone predicate summaries with contradiction pruning. |
| Dataflow & state modeling | Done | Resource state machines (init -> use -> close), auth state transitions, privilege level tracking. Generic Transfer trait over bounded lattices with guaranteed convergence. |
| Monotone taint analysis | Done | Replaced BFS taint engine with a forward worklist dataflow analysis over a finite TaintState lattice. Multi-origin tracking, dual validated-must/may sets, JS/TS two-level solve. Guaranteed termination via lattice finiteness. |
| Attack surface ranking | Done | Deterministic post-analysis scoring of findings by severity, analysis kind, evidence strength, source-kind exploitability, and validation state. Findings sorted by score before truncation so max_results keeps the most important results. |
| Inline suppressions | Done | nyx:ignore and nyx:ignore-next-line comments with wildcard matching, all 10 languages supported. --show-suppressed flag for visibility. |
| Low-noise prioritization | Done | Category filtering, rollup grouping for high-frequency rules, configurable LOW budgets. Quality-category findings hidden by default. |
| Pattern-level confidence | Done | Explicit High/Medium/Low confidence on every AST pattern. Confidence flows into output alongside severity and rank score. |
| AST pattern overhaul | Done | 30+ new patterns across all languages, 11 broken query fixes, namespaced IDs, severity recalibration. |
| Feature | Description |
|---|---|
| Controlled dynamic execution | Local sandbox: identify entry points, spin up test harnesses, inject payloads, detect runtime crashes and command execution. Deterministic automated exploit validation -- static finds exec(user_input), dynamic confirms it with ; id. |
| Fuzzing integration | libFuzzer (C/C++), cargo-fuzz (Rust), go-fuzz, HTTP fuzzing harness. Static engine identifies interesting functions, fuzzer targets only those. |
| Feature | Description |
|---|---|
| Semantic similarity | Embeddings for finding similar vulnerability patterns across codebases. |
| LLM reasoning | AI-assisted detection of non-obvious logic bugs. |
| Exploit refinement | Automated loops to refine and validate exploit chains. |
| Area | Details |
|---|---|
| Output formats | JUnit XML, HTML report generator |
| Language coverage | Expanded taint rules per language |
| Rule updates | Remote rule feed with signature verification |
| UX | Smart file-watch re-scan |
Community feedback shapes priorities -- please open an issue to discuss proposed changes.
Full documentation is available in the docs/ directory:
- Installation — cargo, binaries, CI tips
- Quick Start — Your first scan in 60 seconds
- CLI Reference — Every flag and subcommand
- Configuration — Config file schema, custom rules
- Output Formats — Console, JSON, SARIF; exit codes
- Detector Overview — How the four detector families work
- Taint Analysis — Cross-file source-to-sink dataflow
- CFG Structural — Auth gaps, unguarded sinks, resource leaks
- State Model — Resource lifecycle, authentication state
- AST Patterns — Tree-sitter structural matching
- Rule Reference — Per-language rule listings with examples
Pull requests are welcome. To contribute:
- Fork the repository and create a feature branch.
- Adhere to
rustfmtand ensurecargo clippy --all -- -D warningspasses. - Add unit and/or integration tests where applicable (
cargo testshould remain green). - Submit a concise, well-documented pull request.
Please open an issue for any crash, panic, or suspicious result -- attach the minimal code snippet and mention the Nyx version.
See CONTRIBUTING.md for full guidelines, including how to add new rules and support new languages.
Nyx is licensed under the GNU General Public License v3.0 (GPL-3.0).
This ensures that all modified versions of the scanner remain free and open-source, protecting the integrity and transparency of security tools.
See LICENSE for full details.