diff --git a/CHANGELOG.md b/CHANGELOG.md index ae32ad5f..f0771ccd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -70,7 +70,7 @@ A focused release on three fronts: an attack-surface map and chain composer that ### License -- **Internal license grants documentation** at `LICENSE-GRANTS.md`. Grant 1 covers Nyx Pro derived works (renamed to reflect the Nyctos rebrand). The repo stays GPL-3.0-or-later; the grants document scope of internal product licensing. +- **Internal license grants documentation** at `LICENSE-GRANTS.md`. Grant 1 covers Nyctos derived works. The repo stays GPL-3.0-or-later; the grants document scope of internal product licensing. ## [0.7.0] - 2026-05-11 diff --git a/README.md b/README.md index cbda3276..81c7d5a9 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@
- nyx + NYX **A local-first security scanner with a browser UI. Scan your repo and triage in your browser, with no cloud and no account.** @@ -234,12 +234,12 @@ Limitations: ## Documentation -Browse the full docs site at **[elicpeter.github.io/nyx](https://elicpeter.github.io/nyx/)**. +Browse the full docs site at **[nyxscan.dev/docs](https://nyxscan.dev/docs/)**. -- [Quick Start](https://elicpeter.github.io/nyx/quickstart.html) · [CLI Reference](https://elicpeter.github.io/nyx/cli.html) · [Installation](https://elicpeter.github.io/nyx/installation.html) -- [`nyx serve`](https://elicpeter.github.io/nyx/serve.html) · [Output Formats](https://elicpeter.github.io/nyx/output.html) · [Configuration](https://elicpeter.github.io/nyx/configuration.html) -- [How it works](https://elicpeter.github.io/nyx/how-it-works.html) · [Detectors](https://elicpeter.github.io/nyx/detectors.html) ([Taint](https://elicpeter.github.io/nyx/detectors/taint.html), [CFG](https://elicpeter.github.io/nyx/detectors/cfg.html), [State](https://elicpeter.github.io/nyx/detectors/state.html), [AST Patterns](https://elicpeter.github.io/nyx/detectors/patterns.html)) -- [Rule Reference](https://elicpeter.github.io/nyx/rules.html) · [Language Maturity](https://elicpeter.github.io/nyx/language-maturity.html) · [Advanced Analysis](https://elicpeter.github.io/nyx/advanced-analysis.html) · [Auth Analysis](https://elicpeter.github.io/nyx/auth.html) +- [Quick Start](https://nyxscan.dev/docs/quickstart.html) · [CLI Reference](https://nyxscan.dev/docs/cli.html) · [Installation](https://nyxscan.dev/docs/installation.html) +- [`nyx serve`](https://nyxscan.dev/docs/serve.html) · [Output Formats](https://nyxscan.dev/docs/output.html) · [Configuration](https://nyxscan.dev/docs/configuration.html) +- [How it works](https://nyxscan.dev/docs/how-it-works.html) · [Detectors](https://nyxscan.dev/docs/detectors.html) ([Taint](https://nyxscan.dev/docs/detectors/taint.html), [CFG](https://nyxscan.dev/docs/detectors/cfg.html), [State](https://nyxscan.dev/docs/detectors/state.html), [AST Patterns](https://nyxscan.dev/docs/detectors/patterns.html)) +- [Rule Reference](https://nyxscan.dev/docs/rules.html) · [Language Maturity](https://nyxscan.dev/docs/language-maturity.html) · [Advanced Analysis](https://nyxscan.dev/docs/advanced-analysis.html) · [Auth Analysis](https://nyxscan.dev/docs/auth.html) --- diff --git a/assets/nyx-readme-header.png b/assets/nyx-readme-header.png new file mode 100644 index 00000000..a692d763 Binary files /dev/null and b/assets/nyx-readme-header.png differ diff --git a/assets/nyx-readme-header.svg b/assets/nyx-readme-header.svg new file mode 100644 index 00000000..f1b55a3b --- /dev/null +++ b/assets/nyx-readme-header.svg @@ -0,0 +1,24 @@ + + NYX + NYX security scanner. + + + + + + + + + + + + + diff --git a/docs/configuration.md b/docs/configuration.md index eaf610b9..ccc8d8a5 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -65,6 +65,13 @@ excluded_extensions = ["foo", "jpg"] | `scan_hidden_files` | bool | `false` | Scan dot-files | | `include_nonprod` | bool | `false` | Keep original severity for test/vendor paths | | `enable_state_analysis` | bool | `true` | Enable 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"`. | +| `enable_auth_analysis` | bool | `true` | Enable auth-state analysis within the state engine. When false, only resource lifecycle findings (leak, use-after-close, double-close) are produced. | +| `enable_panic_recovery` | bool | `false` | Catch per-file analysis panics as warnings and continue. When false, a panic aborts the scan, preserving the loud-fail behaviour for users debugging engine bugs. | +| `enable_auth_as_taint` | bool | `false` | Fold auth analysis into the SSA/taint engine via `Cap::UNAUTHORIZED_ID`. Off while the standalone path still carries stable detection. | +| `verify` | bool | `true` | Run dynamic verification on each `Confidence >= Medium` finding after the static pass. Requires the binary to be built with `--features dynamic`. CLI overrides: `--verify` / `--no-verify`. | +| `verify_all_confidence` | bool | `false` | Extend dynamic verification to findings below `Confidence::Medium`. Intended for corpus-building, not production scans. CLI: `--verify-all-confidence`. | +| `verify_backend` | string | `"auto"` | Sandbox backend for dynamic verification. `"auto"` picks docker when available else process; `"docker"` requires docker; `"process"` runs in-process (same as `--unsafe-sandbox`). | +| `harden_profile` | string | `"standard"` | Process-backend hardening profile. `"standard"` engages `PR_SET_NO_NEW_PRIVS` + `setrlimit(RLIMIT_AS)` on Linux; `"strict"` adds namespace unshare, chroot to workdir, and a default-deny seccomp filter on Linux, plus `sandbox-exec` wrapping on macOS keyed off the finding's expected cap. | ### `[database]` @@ -119,6 +126,7 @@ Configuration for the local web UI (`nyx serve`). | `auto_reload` | bool | `true` | Auto-reload UI when scan results change | | `persist_runs` | bool | `true` | Persist scan runs for history view | | `max_saved_runs` | int | `50` | Maximum number of saved runs | +| `triage_sync` | bool | `true` | Auto-sync triage decisions to `.nyx/triage.json` in the project root so changes can be committed to git. | ### `[runs]` @@ -173,10 +181,10 @@ 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. +`NYX_SYMEX_INTERPROC`, `NYX_CONTEXT_SENSITIVE`, `NYX_BACKWARDS`, +`NYX_PARSE_TIMEOUT_MS`, `NYX_SMT`); those env vars are still honored as a +fallback default when nyx is used as a library (no CLI entry point), but the +config/CLI surface is the stable path. | Field | Type | Default | Description | |-------|------|---------|-------------| @@ -185,6 +193,8 @@ the stable path. | `context_sensitive` | bool | `true` | k=1 context-sensitive callee inlining for intra-file calls | | `backwards_analysis` | bool | `false` | Demand-driven backwards taint walk from sinks (adds scan time; default off) | | `parse_timeout_ms` | int | `10000` | Per-file tree-sitter parse timeout; `0` disables the cap | +| `max_origins` | int | `32` | Maximum taint origins retained per lattice value. Excess origins are dropped deterministically (sorted by source location) and an `OriginsTruncated` engine note is recorded. CLI: `--max-origins`. | +| `max_pointsto` | int | `32` | Maximum abstract heap objects retained per intra-procedural points-to set. Excess objects are dropped and a `PointsToTruncated` engine note is recorded. CLI: `--max-pointsto`. | **`[analysis.engine.symex]`** sub-section: @@ -208,11 +218,33 @@ CLI flag map (each pair is `--enable / --no-enable`): | `symex.cross_file` | `--cross-file-symex` / `--no-cross-file-symex` | | `symex.interprocedural` | `--symex-interproc` / `--no-symex-interproc` | | `symex.smt` | `--smt` / `--no-smt` | +| `max_origins` | `--max-origins ` | +| `max_pointsto` | `--max-pointsto ` | **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. +### `[chain]` + +Bounded-DFS path search across taint findings. Emits multi-step attack chains when several findings link through shared SSA values or call edges. + +| Field | Type | Default | Description | +|-------|------|---------|-------------| +| `max_depth` | int | `4` | Maximum per-finding hops in a single chain path. | +| `min_score` | float | `9.5` | Score threshold; chains below this value are dropped. | +| `reverify_top_n` | int | `5` | Only the top-N chains by score are eligible for composite dynamic re-verification. `0` disables composite re-verification. | + +### `[telemetry]` + +Sampling policy for the on-disk event log written by dynamic verification (`~/.cache/nyx/dynamic/events.jsonl`). Confirmed and Inconclusive verdicts are calibration-critical and kept by default; other verdict statuses can be downsampled to bound log growth. Decisions are seeded by `spec_hash` for determinism. See `docs/dynamic.md` for the on-disk schema and `NYX_NO_TELEMETRY=1` opt-out. + +| Field | Type | Default | Description | +|-------|------|---------|-------------| +| `keep_all_confirmed` | bool | `true` | Always retain `Confirmed` verdicts. | +| `keep_all_inconclusive` | bool | `true` | Always retain `Inconclusive` verdicts. | +| `sample_rate_other` | float | `1.0` | Retention probability for verdicts not covered by the keep-all flags. `1.0` keeps everything, `0.0` drops everything. | + ### `[detectors.data_exfil]` Per-project tuning for the `taint-data-exfiltration` rule. All fields are optional. @@ -354,7 +386,7 @@ nyx config show Config is validated after loading and merging. Validation checks include: -- Server port must be 1–65535 +- Server port must be 1 to 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 diff --git a/src/dynamic/sandbox/mod.rs b/src/dynamic/sandbox/mod.rs index c75cdfab..07426ff4 100644 --- a/src/dynamic/sandbox/mod.rs +++ b/src/dynamic/sandbox/mod.rs @@ -837,7 +837,7 @@ fn run_firecracker( ) -> Result { #[cfg(feature = "firecracker")] { - return firecracker::run(_harness, _payload_bytes, _opts); + firecracker::run(_harness, _payload_bytes, _opts) } #[cfg(not(feature = "firecracker"))] { diff --git a/src/fmt.rs b/src/fmt.rs index 25946ef3..4072e793 100644 --- a/src/fmt.rs +++ b/src/fmt.rs @@ -192,7 +192,7 @@ pub fn render_welcome() -> String { for line in LOGO { out.push_str(&format!( " {}\n", - style(line).true_color(114, 243, 215).bold() + style(line).true_color(46, 160, 103).bold() )); } diff --git a/src/state/lattice.rs b/src/state/lattice.rs index 581f9c2b..4a0b9f48 100644 --- a/src/state/lattice.rs +++ b/src/state/lattice.rs @@ -4,7 +4,6 @@ /// - `join` is commutative, associative, and idempotent /// - `bot()` is the identity for `join` /// - `leq(a, b)` iff `join(a, b) == b` -#[allow(dead_code)] pub trait Lattice: Clone + Eq + Sized { /// Bottom element (least information / unreachable). fn bot() -> Self; @@ -28,7 +27,6 @@ pub trait Lattice: Clone + Eq + Sized { /// - `meet(a, b) ⊑ a` and `meet(a, b) ⊑ b` /// - `widen(a, b) ⊒ join(a, b)` (widening is at least as imprecise as join) /// - Ascending chains under `widen` stabilize in finite steps -#[allow(dead_code)] pub trait AbstractDomain: Lattice { /// Top element (no information / maximally imprecise). fn top() -> Self;