HQ-Axiom/axiom-pentest-core
GitHub: HQ-Axiom/axiom-pentest-core
一款自托管、离线优先的渗透测试报告与 AppSec 证据控制平台,支持多源扫描结果导入、确定性去重、合规映射和防篡改审计日志。
Stars: 0 | Forks: 0
# AXIOM-Pentest-Core
Local-first, evidence-driven security-testing platform for **authorized** targets, local labs, and CTFs.


-339933.svg)



[](https://github.com/HQ-Axiom/axiom-pentest-core/actions/workflows/ci.yml)
## TL;DR (30 seconds)
- **What:** Self-hosted workspace for authorized pentest engagements. Runs your existing OSS scanners (Semgrep / Nuclei / Trivy / gitleaks / osv-scanner) under one `authorization.yml`, imports SARIF / Burp / GHAS / GitLab / CSV / Nessus findings, dedupes deterministically, triages with a hash-chained audit log, exports MD / HTML / PDF / SARIF / JSON reports.
- **Why interesting:** Authorization is enforced by the engine (kill-switch, RPS limit, scope, hard refusals — in code, not policy). No telemetry, no phone-home, no automatic outbound — the only network feature is the opt-in `axiom sca` OSV.dev advisory lookup (skippable with `--dry-run`). **One complete Apache-2.0 public version — no Pro/Community split, no feature paywall (P9.0).**
- **Included for everyone:** every scanner, every importer (incl. CSV / Nessus), dedupe, triage, risk scoring, **Markdown / HTML / PDF reports** + `--brand`, SARIF / JSON exports, §5.4 compliance mapping (OWASP / ASVS / PCI / ISO), **Jira / GitHub / GitLab ticket draft export** (dry-run), hash-chained audit log + **`audit anchor`**, `axiom verify`, the loopback-only **AXIOM Local Console** (the official local GUI; plus an advanced read-only single-workspace dashboard).
- **Public in this build (no edition/paywall):** `axiom portfolio summary/workspaces/risks/dedupe` and `axiom metrics snapshot/list/show` run with no `AXIOM_EDITION`/license.
- **Roadmap / not bundled in this public repo yet (honest, not a paywall):** `portfolio export`, the cross-workspace ticket bundle, `portfolio metrics`, `metrics diff/trend/mttr/prune`, and signed-artefact *issuance* depend on optional overlay packages not in this repo — invoking those reports "not included in this public build yet".
- **Try it in 60 seconds:**
git clone https://github.com/HQ-Axiom/axiom-pentest-core.git
cd axiom-pentest-core
pnpm install && pnpm -r build
node packages/cli/bin/axiom.mjs demo --json
node packages/cli/bin/axiom.mjs report -w demo-juice -f md
- **Status:** beta. Latest **[signed GitHub Release: v0.10.6](https://github.com/HQ-Axiom/axiom-pentest-core/releases/tag/v0.10.6)** (source tarball + SBOM + SHA256SUMS + detached Ed25519 signatures + public key). Windows **and** Linux install are verified in CI (install-smoke on `windows-latest` + `ubuntu-latest`). A guided **noob-safe browser GUI** (Engagement Setup → manual findings → branded MD/HTML/PDF reports, no terminal needed) is included. AXIOM stays **local-first**: loopback-only Local Console, **no automatic scanning, no telemetry, no external dashboard scripts** — scan workflows run only when an authorized user explicitly starts them, on systems you own or are authorized to test. One complete public version — **no Pro/Community split, no feature paywall** (P9.0). Not on npm / Docker Hub / GHCR yet. A few heavier subsystems (portfolio export / trend analytics / signing issuance) are not implemented in this build yet (roadmap, never a paywall). Release history in [`CHANGELOG.md`](CHANGELOG.md).
- **Looking for:** 3–5 pilot partners (DACH / EU boutique pentest firms, internal AppSec teams that can't use SaaS). 2-week pilot, no purchase obligation, no data upload. See [`docs/PILOT_OUTREACH_PACK.md`](docs/PILOT_OUTREACH_PACK.md).
## Why AXIOM?
You already run Burp, Snyk, Semgrep, Trivy, CodeQL, or some subset. You triage the same SQL injection three times — once per tool — into a spreadsheet that resets every re-scan.
AXIOM is not a replacement for any of them. AXIOM is the layer above:
- **Runs** OSS scanners (Semgrep, Nuclei, Trivy, gitleaks, osv-scanner) under one `authorization.yml` with scope, RPS limit, kill-switch, and hard refusals enforced by the engine — not by convention.
- **Imports** SARIF / XML / JSON from the commercial tools you already pay for. `axiom import sarif` (any v2.1.0 producer: Snyk, CodeQL, Semgrep Pro, gitleaks…), `axiom import burp` (Burp Pro XML + Burp Enterprise JSON), `axiom import ghas --source code-scanning|dependabot` (GitHub Advanced Security file exports), `axiom import gitlab --type sast|dependency|secret|dast` (GitLab Security reports). `axiom import status` lists imported batches and provenance. All importers are file-local: AXIOM never calls GitHub or GitLab APIs itself — operators feed `gh api …` / `glab api …` outputs, which keeps imports offline-testable.
- **Maps to compliance frameworks** OWASP Top 10 2021, ASVS L1/L2, PCI-DSS 6.5 / 4.0, ISO 27001:2022 — report §5.4 *Compliance Coverage* in both Markdown and HTML. Anti-hallucination: unknown stays `unmapped`, never guessed. Editable via `packages/reporter/src/compliance/mappings.yml`.
- **Dedupes** findings deterministically across tools via a 5-key selector tuple. 54.5 % noise reduction on Juice Shop.
- **Triages** with a 5-status workflow (`open`, `triaged`, `confirmed`, `false_positive`, `wont_fix`) that **carries decisions forward across re-scans**. Reviewers see only new deltas.
- **Audits** every state change in a SHA-256 hash-chained log. `axiom audit verify` walks the chain. Triage exports ship with a tamper-evident `_integrity` block.
- **Reports** Markdown, HTML, and SARIF v2.1.0 with `partialFingerprints`, `kind`, `guid`, and `suppressions[]` for GitHub Code Scanning. One PR check.
- **Trend / portfolio analytics** (Phase E4 — workspace snapshots, eight-class diff, time-series trend, MTTR, cross-workspace portfolio rollup). **In the public build (no edition gate):** `axiom portfolio summary/workspaces/risks/dedupe` and `axiom metrics snapshot/list/show` run for everyone. **Roadmap (optional overlay, not bundled here):** `portfolio export`, the cross-workspace ticket bundle, `portfolio metrics`, and `metrics diff/trend/mttr/prune` report "not included in this public build yet" — candidates for a future public port, never a paywall.
- **Verifies signed artefacts** (`axiom verify`) fully offline — reports, SARIF exports, ticket bundles, and release manifests, with the public key pinned out-of-band. Public **releases** are signed with the production **Ed25519** key by the maintainers (see *Verifying signed releases* below). Operator-side signing **issuance** (the `sign` CLI surface, incl. cosign / Rekor) is **not wired into this public build yet** — a roadmap item, never a paywall. No automatic outbound.
Self-hosted, single-binary-chain, zero telemetry, no background cloud calls (the opt-in `axiom sca` OSV.dev lookup is the sole network feature), Apache-2.0. No license key, no SaaS lock-in.
What AXIOM does **not** claim: it does not replace Burp's Repeater or Snyk's vuln database or Semgrep's rule engine or Nuclei's templates. See [`docs/COMPETITIVE_POSITIONING.md`](docs/COMPETITIVE_POSITIONING.md) for the eleven-tool honest comparison and the five anti-claims.
## New to AXIOM?
👉 **Tutorial:** [`docs/GETTING_STARTED.md`](docs/GETTING_STARTED.md) — von 0 auf ersten Report in 10 Minuten, mit copy-paste Befehlen für jeden Schritt. Empfohlen für jeden, der AXIOM zum ersten Mal aufsetzt.
This repository is **public on GitHub** at [`github.com/HQ-Axiom/axiom-pentest-core`](https://github.com/HQ-Axiom/axiom-pentest-core). Clone via:
git clone https://github.com/HQ-Axiom/axiom-pentest-core.git
cd axiom-pentest-core
Not yet published to **npm** or **Docker Hub / GHCR** — those steps remain operator-gated. There is **no Pro overlay as a product model**: PDF reports, ticket draft export, branding, audit anchor, `portfolio summary/workspaces/risks/dedupe` and `metrics snapshot/list/show` are all part of this public source tree and run with no edition/license. A few overlay-only surfaces (`portfolio export`, the cross-workspace ticket bundle, `portfolio metrics`, `metrics diff/trend/mttr/prune`, and signed-artefact issuance) are **not bundled in this public repo yet** — invoking them reports an honest "not included in this public build yet", never a paywall.
## Quickstart (60 seconds)
**One-script setup** (checks Node, sets up pnpm, installs, builds — no admin needed):
# Linux / macOS:
./scripts/setup-linux.sh
# Windows (PowerShell):
.\scripts\setup-windows.ps1
**Or by hand** (use **Node 20.18.0** from `.nvmrc`, not Node 24):
# Inside the repo:
pnpm install && pnpm -r build
node packages/cli/bin/axiom.mjs doctor # pre-flight check
node packages/cli/bin/axiom.mjs demo # canned workspace with 6 findings + 2 snapshots
node packages/cli/bin/axiom.mjs report -f md -w demo-juice
node packages/cli/bin/axiom.mjs console --open # browser console (create the first admin in the GUI)
Every command runs offline except the opt-in `axiom sca` OSV.dev advisory lookup (`--dry-run` skips its network calls). Cross-platform install notes: [`docs/INSTALL.md`](docs/INSTALL.md).
New here? **[First 10 minutes guide](docs/FIRST_10_MINUTES.md)** — setup → admin → report → verify, copy-paste.
## Local Console preview
The browser console is **loopback-only** (127.0.0.1), with **no telemetry and no
third-party scripts**. From the Console you can import evidence, manage findings,
generate branded MD/HTML/PDF reports — and **explicitly start authorized scan workflows**.
AXIOM **never scans automatically**: a scan runs only when an authorized user
starts it and stays within the scope you authorize. _Only use AXIOM on systems
you own or have explicit written permission to test._
Start the official GUI with:
node packages/cli/bin/axiom.mjs console --open
It has login + RBAC, authorized scan workflows, findings, reports, audit views,
and admin/account flows. The screenshots below are the **real authenticated
Local Console** (a throwaway local admin + the offline `axiom demo` workspace —
no real target, no real data):
| New Scan | Authorization preview (no scan runs) |
|---|---|
|  |  |
| Cross-workspace portfolio (demo data) |
|---|
|  |
### Advanced single-workspace Dashboard
`axiom dashboard -w ` opens a lightweight **read-only, single-workspace**
view for local inspection. It is **not** a second product and **not** the primary
GUI — most users should stay in the Local Console.
| Dashboard overview + engagement | Findings |
|---|---|
|  |  |
| Dashboard reports (MD / HTML / PDF) | Generated PDF cover |
|---|---|
|  |  |
### Attach evidence to findings (P5.5)
Attach screenshots, openssl/curl output, Burp dumps, HTTP captures, or any small text/log/json file to a finding. The file is copied into the workspace (your source is untouched), hashed with SHA-256, and recorded with a hash-chained audit event. Metadata flows into MD / HTML / JSON / SARIF reports and the local dashboard.
# Attach
node packages/cli/bin/axiom.mjs evidence add -w my-first \
--finding \
--file \
--kind terminal|screenshot|http|text|json|log|other \
--title "..." --description "..." --json
# List + inspect
node packages/cli/bin/axiom.mjs evidence list -w my-first --finding
node packages/cli/bin/axiom.mjs evidence show -w my-first --evidence
Storage: `workspaces//evidence/attachments//-`. Default size cap 10 MiB (`--max-bytes` to override). Symlinks always refused; directories refused; path traversal stripped. **No upload, no remote storage, no automatic screenshot.** See `docs/EVIDENCE_ATTACHMENTS_USAGE.md`.
### Distribution status
### One complete public version (P9.0 — no Pro split)
As of **v0.10.4**, AXIOM has **no Community/Pro/Enterprise split and no feature paywall.** There is one normal public version, and `axiom --version` reports a plain version string. Every shipped feature works for everyone:
- every scanner, importer (SARIF / Burp / Nuclei / ZAP / GHAS / GitLab / **CSV** / **Nessus**), dedupe, triage, risk scoring;
- **reports in Markdown / HTML / PDF** (PDF is a normal feature now — pure-JS pdfkit renderer, no chromium), plus **safe MD/HTML branding** (`--brand`);
- **SARIF / JSON / Markdown findings exports**;
- **ticket draft export** for Jira / GitHub / GitLab (`axiom ticket export`, dry-run — writes files, never calls an API);
- **hash-chained audit log** + `audit verify` + out-of-band **`audit anchor`** tamper evidence;
- offline signing **verification** (`axiom verify`), the loopback-only **AXIOM Local Console** (plus an advanced single-workspace dashboard), OWASP / ASVS / PCI / ISO compliance mapping.
`portfolio summary/workspaces/risks/dedupe` and `metrics snapshot/list/show` run in this public build. A few overlay-only surfaces (`portfolio export`, cross-workspace ticket bundle, `portfolio metrics`, `metrics diff/trend/mttr/prune`, signed-artefact **issuance**) are **not bundled in this public repo yet** — invoking them reports an honest "not included in this public build yet" (never "requires Pro"). They are candidates for a future public port, not a paywall.
There is no hidden feature gate. Any paid offering would be support / integration / training, never a locked feature.
## Local packaging
P1.4a ships a Dockerfile + a local release script. Nothing is published — all artefacts stay on the build host.
# Plan-only manifest (verifies version, computes SHA-256, writes no artefacts):
node scripts/make-release.mjs --dry-run --json
# Real local release — runs pnpm -r build, pnpm -r test, then pnpm pack the CLI:
node scripts/make-release.mjs
# Optional: build a container image (Node 22 Debian-slim, multi-stage, ~750 MB):
docker build -t axiom-local:0.10.4 .
docker run --rm -v "$PWD/workspaces:/app/workspaces" axiom-local:0.10.4 --version
Or use the wrapper `Makefile`:
make image # docker build -t axiom-local: .
make image-smoke # build + axiom --version + doctor --json + demo with mounted volume
make release-dry # manifest-only dry run
make release # full local release (build + test + pnpm pack)
make verdaccio-smoke # local Verdaccio registry-install proof (skipped without Verdaccio)
make registry-install-smoke # alias for verdaccio-smoke
make help # list all targets
### Container runtime contract
The image is loopback-by-design (D9 / D13): the Local Console refuses to bind on a non-loopback host. CLI commands work fully inside the container. For a smoke run:
docker run --rm -v "$PWD/workspaces:/app/workspaces" axiom-local:0.10.4 demo --json
docker run --rm -v "$PWD/workspaces:/app/workspaces" axiom-local:0.10.4 report -w demo-juice -f pdf -o /app/workspaces/report.pdf
Mounting the host's `workspaces/` directory makes the container's writes visible to subsequent `axiom` calls (on host or container). The auth DB lives at `/root/.axiom` — mount a separate host directory to persist users + sessions across container restarts.
Console-mode inside the container is **deferred to a later P1 step** — the dashboard's hard loopback-bind guard would need a deliberate `AXIOM_DASHBOARD_ALLOW_EXTERNAL_BIND=1` env-path before published-port `docker run -p 18888:18888` makes sense. CLI surface (every `axiom` subcommand) works fine inside the container today.
Output lands in `release-artifacts/` (git-ignored): one `.tgz` per packed workspace + `release-manifest.json` with SHA-256 hashes, the resolved version, git commit, and a paranoia-pass that refuses any artefact path matching `.env` / `.sqlite` / `workspaces/` / `.axiom/`. No `npm publish`, no `docker push`, no tag — the operator decides what happens next.
Container volumes (operator-mounted, not VOLUME-declared so `docker run --rm` works cleanly):
- `/app/workspaces` — per-workspace SQLite ledgers
- `/root/.axiom` — global auth DB (users + sessions)
### Verifying signed releases
**v0.5.1 is the first AXIOM release that officially documents and versions
the P1.5 signed-release flow.** P1.5 turns `make-release.mjs --sign` into a
self-describing, versioned **signed release directory** (default
`dist/releases/axiom-v/`, override with `--out `):
# Release signing (Mode A, offline Ed25519 — no Rekor, no network; maintainer/production key):
axiom keygen # one-time, private key 0600
make release # or: node scripts/make-release.mjs
AXIOM_EDITION=enterprise \
node scripts/make-release.mjs --sign --signer "you@org" \
--out dist/releases/axiom-v0.10.6
The folder contains the tarball, the signed `release-manifest.json` + its
sidecar, `SHA256SUMS`, detached raw Ed25519 `.sig` files, the **public**
key (`axiom-pub.pem`), `provenance.json` and a `README_VERIFY.md`.
Consumers verify **fully offline** (verification is ungated — works in
Community), three independent ways:
# 1. AXIOM-native (the cryptographic root of trust):
axiom verify release --manifest release-manifest.json --key axiom-pub.pem
# 2. Tool-agnostic integrity:
sha256sum -c SHA256SUMS
# 3. Defense-in-depth with stock OpenSSL:
base64 -d SHA256SUMS.sig > /tmp/s.sig
openssl pkeyutl -verify -pubin -inkey axiom-pub.pem -rawin -in SHA256SUMS -sigfile /tmp/s.sig
Pin `axiom-pub.pem` **out of band** — AXIOM never trusts a key embedded
in a sidecar. None of these paths contacts a network or a transparency
log. Full detail + the honest reproducibility caveat:
[`docs/SIGNED_RELEASES.md`](docs/SIGNED_RELEASES.md).
### Productization history (v0.6.0 → v0.7.0 — superseded by P9.0)
Earlier versions (v0.6.x–v0.7.1) experimented with a public-core + private
`axiom-pro` overlay split that gated PDF / ticket bundles / portfolio / metrics /
signed-artefact issuance behind a Pro/Enterprise edition. **P9.0 (v0.7.2) removed
that split entirely**: AXIOM is now one public version with no edition gate and no
feature paywall. PDF, ticket draft export, branding and audit anchor are public;
portfolio, trend metrics and signed-artefact issuance are simply not implemented in
this public build yet (roadmap, not locked). The old overlay packages and
`FEATURE_REQUIRES_PRO` paths are historical only.
#### Public OSS Distribution readiness (released in v0.6.2)
As of v0.6.2, every public package is verifiably packable into a
clean npm tarball — proven on every release-cut by
`make public-distribution-smoke`:
# Per-package pack + invariant scan (zero Pro code, zero secrets,
# zero operator data; SHA-256 recorded). Tarballs land in
# dist/public-pack-audit/ (git-ignored).
make public-pack-audit
# → status: ok (fails=0, warns=0)
# → 13 packages, 9.7 KB–199.6 KB each
# Full end-to-end smoke (split-audit + private-profile-check +
# pack-audit; add --docker if axiom-local:0.10.4 image is built).
make public-distribution-smoke
# Direct invocations (with JSON output) are also supported:
node scripts/public-npm-pack-audit.mjs --json
node scripts/public-distribution-smoke.mjs --json
# Optional Docker public-image smoke (proves the image carries the public
# source only — zero private overlay packages on disk).
make image # if not already built
make public-image-smoke
The full **What is** and **What isn't** in each tarball is contracted
in [`docs/public-oss-distribution.md`](docs/public-oss-distribution.md).
Every public `package.json` still carries `"private": true` — flipping
that flag is the single deliberate operator gesture that authorises a
public `npm publish`. **Public source is live on GitHub
([`HQ-Axiom/axiom-pentest-core`](https://github.com/HQ-Axiom/axiom-pentest-core),
since 2026-06-07), and a signed GitHub Release
([v0.7.0](https://github.com/HQ-Axiom/axiom-pentest-core/releases/tag/v0.7.0))
is published. No `npm publish` has happened. No Docker image published.**
# Public release smoke (ephemeral signing key in $TMPDIR, no trust-roots):
make release-smoke-public
# Private release smoke (bundles release/private/production-trust-roots.example.json):
make release-smoke-private
# Both profiles + customer-verify simulation + leak scan in one command:
make release-smoke
`make release-smoke` emits signed releases into `dist/release-smoke*/`
(git-ignored), runs `axiom verify release` against each, asserts that
the private manifest's `trust_roots.sha256` matches the shipped
`production-trust-roots.json`, runs `axiom doctor --json` against the
private trust-roots (expects `production_trust_root:true`), then
re-verifies in a sandboxed `$TMPDIR` (third-party simulation). Schema:
`axiom-release-profile-smoke/v1`. **No network, no Rekor, no push,
no publish.** Full 20-step acceptance gate:
[`docs/release-profile-acceptance-gate.md`](docs/release-profile-acceptance-gate.md).
All five Pro/Enterprise overlay packages — `@axiom/pro-reporter`
(P1.9), `@axiom/pro-ticket-bundle` (P1.11), `@axiom/pro-metrics`
(P1.12 + P1.13), `@axiom/pro-portfolio-export` (P1.14), and
`@axiom/ent-signing` (P1.15) — have been **physically externalised**
out of this repository and live in a separate private `axiom-pro`
overlay repo (no remote, no publish). Public-core is
**Pro-code-free**: zero `packages/pro-*/` or `packages/ent-*/`
directories, zero `@axiom/(pro|ent)-*` reference in any public
`package.json` dependency bucket; enforced by
`scripts/public-split-audit.mjs` (`status:"ok"`, 0 fails, 0
warns) and by the overlay's `overlay-install-from-tarballs.mjs`
smoke. Two further enterprise namespaces (`@axiom/ent-rbac`
P1.16, `@axiom/ent-compliance` P1.17) are vocabulary-reserved
with prospective audit-guard tests; no overlay package on disk
yet (assessment docs in
[`docs/rbac-extraction-assessment.md`](docs/rbac-extraction-assessment.md)
and
[`docs/custom-compliance-extraction-assessment.md`](docs/custom-compliance-extraction-assessment.md)).
## Authorization is non-optional
## What AXIOM is
A coherent pipeline that combines SAST (repo indexer, route mapper, dataflow-light, secrets, SCA),
DAST (passive crawler + active-safe probes for reflection / SQL-error / SSRF / path-traversal /
open-redirect), a Playwright-driven browser verifier (XSS reflection, cookie hygiene, login
recording), session-aware authenticated crawling, declarative business-logic invariants, and
a unified reporting engine (Markdown, HTML, SARIF, JSON) — all gated by a single
authorization manifest and recorded in a per-workspace SQLite ledger with full HTTP evidence
and an append-only audit log.
AXIOM is a **TypeScript monorepo** of 13 packages built with pnpm workspaces. State lives in
each workspace's `.axiom/db.sqlite`; nothing is uploaded anywhere.
## Easiest mode — AXIOM Local Console
If this is your first time, skip the per-stage CLI and use the **Local Console** — a
loopback-only browser wizard that drives the whole pipeline (index → routes → scan → verify
→ report) from a 12-step UI with explicit authorization checkboxes. Same safety enforcement
as the CLI; nothing binds outside `127.0.0.1`.
AX="$(pwd)/packages/cli/bin/axiom.mjs"
node "$AX" console --open
See [`docs/gui-quickstart.md`](docs/gui-quickstart.md) for the full walkthrough. For
unattended / CI runs, the equivalent one-liner is `axiom scan-wizard --url --profile
quick --confirm-authorization`.
## Quick start
### Prerequisites
- **Node 20.18.0 (recommended/tested — see `.nvmrc`).** The floor is 20.10, but
use **20.18.0**. **Do not use Node 24** — the native modules (`better-sqlite3`,
`argon2`) have no prebuilds for it yet and `pnpm install` will fail to build
them (this bites Windows hardest). `nvm use` picks up `.nvmrc` automatically.
- **pnpm 9+** — `corepack enable && corepack prepare pnpm@9.12.0 --activate`.
If corepack errors with `EPERM` (common on Windows without admin), install
pnpm with npm instead: `npm install -g pnpm@9.12.0`.
- **Build tools** for `better-sqlite3` / `argon2` (Linux apt: `build-essential
python3`; macOS: `xcode-select --install`; Windows: see `docs/INSTALL.md`).
- **Optional:** chromium for browser-verify — `pnpm exec playwright install chromium`
The Quickstart below sets `$AX` to the absolute path of the CLI entry point so subsequent
examples work regardless of `cwd`. For convenience you can also `alias axiom="node $AX"`.
Every later example in this README assumes `$AX` is set.
git clone https://github.com/HQ-Axiom/axiom-pentest-core.git
cd axiom-pentest-core
nvm use && corepack enable && pnpm install && pnpm -r build
pnpm -r test # unit tests across all packages
# optional: install chromium for browser-agent verification (~250 MB, one-time)
pnpm exec playwright install chromium
AX="$(pwd)/packages/cli/bin/axiom.mjs"
node "$AX" doctor # env self-check
`axiom doctor` validates Node version, pnpm, the native `better-sqlite3` binding, YAML support,
write permissions, and (warn-only) the chromium binary. A green doctor is a precondition for
every other command. When a check fails, doctor now prints an `install hint:` line with the
platform-specific command — paste that line and run it.
## First scan against OWASP Juice Shop (E2E)
End-to-end run against a local Juice Shop with authenticated crawling and browser verification:
# One-time: clone the Juice Shop source so the indexer / route-mapper have code to walk
git clone https://github.com/juice-shop/juice-shop.git ~/juice-shop
docker run --rm -d --name juice-shop -p 3000:3000 docker.io/bkimminich/juice-shop
node "$AX" workspace create juice-shop-local --seed-auth
# Edit workspaces/juice-shop-local/authorization.yml — confirm scope, owner, window
node "$AX" auth show -w juice-shop-local
# HTTP-only login: POSTs credentials, extracts JWT from response body,
# synthesizes a Playwright-compatible storage state. Never persists secrets.
node "$AX" auth login -w juice-shop-local --role admin \
-u http://127.0.0.1:3000/rest/user/login \
--field email=admin@juice-sh.op --field password=admin123 \
--bearer-path authentication.token
# Full pipeline: index -> routes -> secrets -> http_tester -> reporter
node "$AX" run -w juice-shop-local \
-r ~/juice-shop -b http://127.0.0.1:3000 \
--active-safe --as admin --no-sca
# Browser-verify every reflection finding (single Chromium pass)
node "$AX" browser verify-xss -w juice-shop-local --all-reflections
# Render a Markdown report
node "$AX" report -w juice-shop-local -f md
docker rm -f juice-shop
Authenticated crawl reaches **+60 % more 2xx routes** and **-70 % 401s** vs. anonymous baseline
on Juice Shop. Browser verification reduces reflection false-positives by **~87.5 %** on the
same target.
**Shortcut:** the bash script `scripts/demo-juice-shop.sh` automates all of the above — see
`docs/checkpoints.md` for the Phase 6 entry.
## CLI surface
40+ top-level commands, in workflow order (run `axiom --help` for the authoritative list; the table below covers the orchestrating commands; the 5 standalone external-adapter commands `axiom semgrep / nuclei / trivy / gitleaks / osv-scanner` are documented under §"Adapters" — they're each a thin wrapper around the matching binary, used for adapter-specific debugging; the unified entry-point is `axiom adapters run-all`):
| Command | Purpose |
|---|---|
| `axiom init` | First-run helper; prints next steps and links to docs |
| `axiom doctor` | Environment self-check (Node, pnpm, sqlite, yaml, chromium) |
| `axiom workspace create / list / info` | Create or inspect a workspace (DB, audit log, evidence dir) |
| `axiom auth init / show / inspect` | Seed and validate an `authorization.yml` manifest |
| `axiom auth login` | HTTP-only login: capture session + bearer for a role |
| `axiom auth session list / show / remove` | Manage captured per-role storage states |
| `axiom index run / list / show` | Walk a repo: files, projects, frameworks, entry points, deps |
| `axiom routes run / list / show` | Extract HTTP routes (Express, FastAPI, OpenAPI) from indexed code |
| `axiom http crawl` | Authorized HTTP crawl, optionally `--as `, `--active-safe` |
| `axiom http requests` | Inspect captured requests / responses (filter by role, status) |
| `axiom scan` | Single-shot: scope-check + crawl + active-safe probes |
| `axiom run` | Full agent pipeline: index -> routes -> (secrets, sca) -> http -> report |
| `axiom secrets scan` | Local secret scanner (always masks values before persistence) |
| `axiom sca` | Dependency CVE check via OSV.dev (npm, PyPI, Go, Maven, ...) |
| `axiom dataflow scan` | SAST-light: source-to-sink taint heuristics (JS / TS / Python) |
| `axiom invariants validate / run` | Declarative business-logic rules over captured responses |
| `axiom hypotheses idor` | Two-role response diff for IDOR / BOLA detection |
| `axiom browser status / screenshot` | Chromium status; on-demand screenshot of an authorized URL |
| `axiom browser record-login` | Headed Playwright session-capture (storage state per role) |
| `axiom browser verify-xss [] [--all-reflections]` | Live-DOM XSS / reflection verifier |
| `axiom correlate` | Link findings back to mapped routes (path-anchored regex) |
| `axiom coverage` | Route-coverage report (matched vs. uncovered routes) |
| `axiom findings list / show / export` | Inspect / filter findings; export md / json / sarif |
| `axiom findings dedupe / clusters / cluster {show,split,triage,triage-bulk}` | Cluster duplicate findings (5 deterministic keys), reversible split, MAX-severity policy |
| `axiom findings triage / triage-bulk / triage-history` | Per-finding decisions: open / accepted / dismissed / false_positive / wont_fix; cluster propagation; audit-only history |
| `axiom findings triage-policy {validate,apply}` | Declarative auto-triage rules (YAML v1) — protects local direct decisions by default |
| `axiom findings triage-export / triage-import` | Portable JSON for sharing decisions across workspaces (stable selectors, --force override) |
| `axiom findings scans-list / diff / triage-carryover` | Cross-run delta + propagate triage from earlier runs (CI re-scan workflow) |
| `axiom adapters {status, run-all}` | Unified entry point for 5 OSS scanners + native HTTP crawl. `--profile {quick,full,deep,ci}` presets, `--parallel`, `--fail-on ` exit-code policy |
| `axiom replay ` | Emit a curl (or Playwright fetch stub) to reproduce a finding |
| `axiom report -f md\|html` | Full 12-section report (incl. 5.1 Consolidated Findings, 5.2 Triage Status) with evidence appendix |
| `axiom console --open` | **AXIOM Local Console** — the official local GUI (multi-user, loopback-only) |
| `axiom dashboard -w` | Advanced read-only single-workspace view (secondary; most users want `axiom console`) |
| `axiom audit verify -w [--json]` | Verify the workspace's hash-chained NDJSON audit log; non-zero exit on a broken chain |
| `axiom kill [--clear]` | Drop / clear the kill-switch sentinel — refuses subsequent runs |
Run any command with `--help` for full options.
## Architecture
+---------------------------+
| axiom CLI (commander) |
+-------------+-------------+
|
+----------------+----------------+
| |
+----------v----------+ +------------v-----------+
| @axiom/orchestr. | | AuthGate / KillSw |
| topo + budgets | | ScopeEnforcer |
+----------+----------+ +------------+-----------+
| |
+-----------+----------+----------+-----------+----------+
| | | | | |
v v v v v v
+-----+ +--------+ +--------+ +---------+ +---------+ +--------+
|index| |route- | |dataflow| |sca- | |http- | |browser-|
|er | |mapper | |-light | |secrets | |tester | |agent |
+-----+ +--------+ +--------+ +---------+ +----+----+ +---+----+
| |
+----------+---------+
v
+---------+ +---------+
| reporter|<--|business-|
| md/html/| |logic |
| sarif | +---------+
+----+----+
|
+------v-------+
| dashboard | loopback-only
| (zero-dep) |
+--------------+
All packages persist through @axiom/core (SQLite via better-sqlite3)
and share types through @axiom/shared.
13 packages: `shared`, `core`, `cli`, `orchestrator`, `indexer`, `route-mapper`, `http-tester`,
`browser-agent`, `sca-secrets`, `dataflow-light`, `business-logic`, `reporter`, `dashboard`.
See `docs/decisions.md` for ADRs and `docs/checkpoints.md` for the per-phase delivery log.
## Security model
- **Authorization manifest** — Zod-validated YAML with target metadata, scope allowlists,
allowed test types, rate / budget limits, scan window, hard refusals, and operator
attestation. The AuthGate snapshots the parsed manifest into the DB at scan start.
- **Scope enforcement** — Domain (literal + leading-wildcard), IPv4 / IPv6 / CIDR allowlists,
port allowlist, default-deny on private ranges, hard block on cloud-metadata endpoints
(`169.254.169.254`, `fd00:ec2::254`, `metadata.google.internal`, ...).
- **Kill switch** — Presence of `.axiom/KILL_SWITCH` halts every running and future agent
immediately. `axiom kill` toggles it; `axiom kill --clear` removes it.
- **RPS limiter** — Per-host token bucket (default `max_rps_per_host: 5`). Hard cap on
total requests per scan via `max_total_requests`.
- **Budget cap & timeouts** — Per-agent budget, global deadline, hard 2x-budget timeout
enforced by the orchestrator (`runPlan`).
- **Audit log** — Append-only NDJSON at `.axiom/audit.log`. Every agent start, scope decision,
finding write, kill-switch event, and report generation is recorded.
- **Secret masking** — Secret-scanner findings always mask the value before persistence
(`AKIA****...****MPLE`). `axiom auth login` records field **names** only, never values
or tokens.
- **Loopback-only dashboard** — Refuses to bind `0.0.0.0` unless `--allow-external`. Sets
`X-Content-Type-Options: nosniff`, `X-Frame-Options: DENY`, `Referrer-Policy: no-referrer`.
No CDN, no remote scripts, no remote fonts.
- **Hermetic marker probes** — Reflection / open-redirect canaries use the unresolvable
`axiom-canary.invalid` domain; markers carry per-finding `axm_` IDs so they can
be unambiguously attributed in the live DOM later.
## Findings and verification
Each finding carries a `severity` (`info | low | medium | high | critical`), a `confidence`
(`unconfirmed | low | high | verified`), and — once browser-verified — a `verification_status`:
| `verification_status` | Meaning |
|---|---|
| `verified_xss` | Marker rendered in script context (inline `