Rust-first hybrid defensive and offensive security orchestration agent for authorized vulnerability and penetration testing across web, API, mobile (Android), blockchain, cloud, and infrastructure targets.
Defensive and offensive security orchestration agent for authorized vulnerability and penetration testing across platform applications, tools, APIs, and infrastructure.
For a beginner-friendly, step-by-step operations manual, read:
OPERATING_GUIDE.mdCOMMAND.md— every command with a one-line description and a copy-paste example (new users start here)CONTRIBUTING.md— developer workflow and CI gatesCHANGELOG.md— version history
# Clone and build
git clone <repo-url>
cd security-agent
# Validate and build (or just `make check` for all four steps)
cargo fmt --all --check
cargo clippy --all-targets -- -D warnings
cargo test --lib
cargo build --release
# Inspect actual local status
./target/release/security-agent --offline-status# Install Rust inside Termux
pkg install rust
# Clone and run directly on-device
git clone <repo-url> && cd security-agent
cargo run --releasePrerequisites
- Install the Android NDK (r25c or later).
- Add Rust Android targets:
rustup target add aarch64-linux-android # arm64-v8a (modern phones, recommended)
rustup target add armv7-linux-androideabi # armeabi-v7a (older 32-bit devices)
rustup target add x86_64-linux-android # x86_64 emulator- Add NDK clang wrappers to
PATH(or update.cargo/config.tomlwith absolute paths):
export PATH="$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin:$PATH"Build
cargo build --release --target aarch64-linux-androidDeploy via ADB
adb push target/aarch64-linux-android/release/security-agent /data/local/tmp/
adb shell chmod +x /data/local/tmp/security-agent
adb shell /data/local/tmp/security-agentThe resulting binary is fully self-contained — no JVM, no framework, no internet access required at runtime.
For a full file-system → architecture map (layer diagram, per-module
directory, data-flow, and the neural-LM integration map), see
ARCHITECTURE.md.
Federated model (not an unrestricted super-agent):
- Coordinator — plans scoped runs, maps targets to specialists, writes immutable audit records, emits execution plans.
- Specialists — SAST, DAST, API security, dependency risk, cloud/IaC, container/K8s, secrets, malware, compliance, Android/mobile, blockchain/smart-contract.
- Capability Registry — maps specialists to approved tools, supported target types, and allowed techniques.
- Policy Engine — time-bounded engagement profiles, technique allow-lists, deny-list targets, intensity caps, high-impact approval gate.
- Audit Ledger — append-only record of every authorized action; filterable by role and action type.
- Attack-Path Graph — builds threat model (nodes + edges) from a set of findings.
- Retest Scheduler — drift-and-risk-based retest intervals derived from finding risk scores.
- Cognitive Layer (
src/cognition.rs) — advisory reasoning over an already-authorized plan: ranks tasks by expected risk yield, proposes ranked hypotheses about which technique is likely to find what per target type, and reflects on the plan to flag coverage gaps. - Advanced Cognitive Architecture (
src/cognitive_engine.rs) — models the reasoning process itself as cooperating faculties: an explicit, provenance-linked train of thought (observe → hypothesize → imagine → decide → reflect), Bayesian belief revision with Shannon-entropy uncertainty, adversary theory-of-mind predicting an attacker's ranked next moves, salience-weighted attention allocation, metacognition that self-assesses confidence, names knowledge gaps, and decides when to escalate to a human, confidence calibration scoring the agent's priors against realized findings (Brier score / expected calibration error / over- vs under-confidence) and feeding that correction back into live hypothesis confidence via leave-one-out recalibration, and compromise propagation that spreads lateral-movement risk across the attack graph. Exposed via--plan-scan <config> --cognitive-review. - Cognitive Memory (
src/memory_store.rs) — folds the single append-only findings log (src/findings_log.rs) into cognitive memory, so cognition learns across engagements instead of starting blank each run. A scan's findings log (written by--findings-log) loads directly as--cognitive-review --memory <log>input — one format across the whole loop — so hypothesis confidence and attention rise, beliefs get Bayesian-updated by real evidence, and metacognition stops flagging a well-evidenced target as a knowledge gap.
Both cognitive layers are purely advisory — they reason over plans the PolicyEngine/Coordinator have already authorized, and never grant, restrict, execute, or bypass any authorization decision.
| Target Type | Use Case Pack | Default Techniques |
|---|---|---|
WebApp |
webapp-core-pack | PassiveRecon, ConfigurationAudit, DAST |
Api |
api-core-pack | PassiveRecon, ConfigurationAudit, ApiSecurity |
MobileBackend |
mobile-backend-pack (deprecated → api-core-pack) | ConfigurationAudit, ApiSecurity, AndroidStaticAnalysis |
MobileApp |
android-mobile-pack | AndroidStaticAnalysis, MobileRuntime, SecretScan, DependencyAudit |
Cloud |
cloud-posture-pack | ConfigurationAudit, CloudPosture |
Blockchain |
smart-contract-pack | SAST, ThreatModeling, AttackPathAnalysis |
Container |
cloud-posture-pack | ConfigurationAudit, ContainerPosture |
Infrastructure |
cloud-posture-pack | ConfigurationAudit, CloudPosture |
SourceCode |
webapp-core-pack | SAST, SecretScan |
DependencyManifest |
webapp-core-pack | DependencyAudit |
The MobileAndroid specialist uses a dedicated tool set for APK/DEX analysis and runtime instrumentation:
apktool, jadx, mobsf, androguard, frida, objection, apkleaks, apksigner, dex2jar, drozer, qark, mariana-trench, trueseeing, nuclei, semgrep
Authorization and scope:
- Time-bounded engagement profiles
- Explicit in-scope target allow-list (target IDs must be pre-authorized)
- Technique allow-list per engagement
- Explicit deny-list targets
- High-impact approval gate (criticality ≥ 8 + Standard intensity)
- Explicit penetrative-technique approval gate (DAST/API/mobile runtime/exploit validation)
Least-privilege defaults (enforced in AuthorizationOutcome):
- Ephemeral runner required
- Short-lived credentials required
- Shared long-lived credentials forbidden
- Per-tool network egress policy metadata
- Discovery and inventory
- Passive recon and configuration checks
- Source / dependency / static analysis
- Runtime app / API scanning
- Cloud / container / infrastructure posture checks
- Correlation and risk scoring
| Module | Responsibility |
|---|---|
src/mission.rs |
Mission statement constant |
src/model.rs |
Core enums and structs (targets, techniques, engagement profile) |
src/registry.rs |
Capability registry and toolchain pack registry |
src/policy.rs |
Authorization and least-privilege policy engine |
src/workflow.rs |
Ordered workflow stage model |
src/coordinator.rs |
Orchestration, scoped task planning, audit integration |
src/orchestrator.rs |
Turns a plan into an ordered, deduplicated execution schedule (least-invasive first: static → active network → exploitation) |
src/engagement_config.rs |
Zero-dependency parser for --plan-scan engagement config files |
src/execution.rs |
Bounded real execution of StaticLocalAnalysis cataloged tools, run in the orchestrator's scheduled order via execute_plan |
src/tool_adapter.rs |
Per-tool invocation model: builds each tool's concrete argv/output-format from an authorized step + discovered context (AdapterRegistry, ToolAdapter) |
src/runtime.rs |
Concurrent execution runtime: class-ordered bounded concurrency, deterministic output, rate limiting, cancellation, mid-run authorization guard, checkpoint/resume (ExecutionRuntime) |
src/engagement_context.rs |
Discovery blackboard: deduplicated hosts/services/endpoints threaded through the staged pipeline (EngagementContext) |
src/pipeline.rs |
Result-driven staged engagement: runs the schedule class-by-class, folding each stage's discoveries forward (run_engagement_pipeline) |
src/correlation.rs |
Deduplicates and cross-tool-correlates findings, boosting confidence on independent corroboration (correlate) |
src/evidence.rs |
Evidence capture / chain-of-custody: SHA-256 of each tool's output plus provenance (EvidenceRecord, capture) |
src/report.rs |
Engagement deliverables: SARIF 2.1.0, machine JSON summary, and Markdown report (rollups, remediation, attack-path narrative, evidence) — surfaced by --report |
src/secrets.rs |
Credential handling for authenticated tools: redaction-safe Secret, a store resolving ${secret:NAME} references from env/file, and output scrubbing (SecretStore) |
src/scope.rs |
Pre-spawn egress scope enforcement: refuses out-of-scope IPv4/CIDR/URL targets in a tool's argv before it runs (ScopePolicy) |
src/observability.rs |
Structured engagement events + pluggable sinks (JSON-lines/collecting/null) and a progress rollup, emitted live by the runtime (EngagementEvent, EventSink, ProgressSummary) |
src/audit_log.rs |
Append-only on-disk persistence for the audit ledger |
src/audit_db.rs |
Same role as audit_log.rs, backed by the zero-dependency .sadb embedded database instead of JSON Lines |
src/findings.rs |
Unified finding model and normalized risk scorer |
src/ingest.rs |
Turns real tool output (semgrep, SARIF, JSONL) into scored Findings |
src/findings_log.rs |
Append-only on-disk findings log — the single findings format, reused by cognition |
src/findings_db.rs |
Same role as findings_log.rs, backed by .sadb instead of JSON Lines |
src/json.rs |
In-house JSON parser/writer (keeps the crate free of external runtime crates) |
src/sadb.rs (+ src/sadb/) |
Zero-dependency embedded append-only database: pager, heap pages, an immutable-image catalog, and a checksummed-footer transaction boundary with crash recovery. Not SQLite-compatible by design — see the module docs for why |
src/governance.rs |
Append-only audit ledger with role/action filtering |
src/intensity_guard.rs |
Non-blocking intensity advisories for network-tool execution |
src/integrity.rs |
Offline tool-integrity verification against a bundled manifest |
src/advanced.rs |
Attack-path graph builder and retest scheduler |
src/cognition.rs |
Advisory reasoning layer: risk-yield task prioritization, per-target-type hypothesis generation, and reflective plan critique |
src/cognitive_engine.rs |
Advanced cognitive architecture: chained reasoning, Bayesian belief revision, adversary theory-of-mind, attention allocation, metacognition, calibration, and compromise propagation |
src/calibration.rs |
Confidence-calibration tracking: Brier score, reliability bins, expected calibration error, over/under-confidence tendency, and histogram recalibration |
src/calibration_db.rs |
Persists calibration records across runs (via .sadb) so CognitiveEngine::with_calibration has real cross-engagement evidence instead of an empty tracker every run |
src/reasoning_log_db.rs |
Write-only .sadb archive of each --cognitive-review run's full reasoning chain and metacognitive verdict, for after-the-fact review |
src/belief_propagation.rs |
Noisy-OR compromise-risk propagation across the attack graph (lateral movement) |
src/language_model.rs |
Small from-scratch self-attentive, vector-quantized temporal-frequency neural language model (embed → self-attention → DCT → residual VQ codebooks → softmax), SGD-trained then Levenberg-Marquardt-refined on a bundled security corpus; text generation and perplexity scoring |
src/builtin_tools.rs |
Offline built-in substitutes (autopsy, volatility) plus the in-house SHA-256; real local-file analysis, no network |
src/local_analyzers.rs |
Offline forensic substitutes — binwalk (signature/entropy), foremost (carving), bulk_extractor (IOC features), hashdeep (recursive multi-hash + dedup) |
src/network_policy.rs |
NetworkMode egress governance: offline by default, live network/active tools only under the explicit per-invocation --allow-network opt-in |
src/anomaly.rs |
Language-model perplexity as an anomaly lens: flags out-of-domain finding text in the cognitive review |
src/nlu.rs |
Grounded plain-English intent router behind --ask: lexical + semantic mapping of instructions to real capabilities |
src/memory_store.rs |
Folds the append-only findings log into cognitive memory, so cognition learns across engagements from one shared format |
src/compat.rs |
Integration adapter contracts and wire-format envelope (audit + finding records) |
src/roadmap.rs |
Phased rollout model (surfaced by --about) |
src/main.rs |
Offline local runtime entry point (also cross-compiles for Android); includes the --tui interactive terminal UI, built entirely on the same command functions the plain CLI dispatches to |
- Phase 1 — Coordinator, core scanners, and reporting (complete)
- Phase 2 — Cloud, container, and supply-chain specialists (complete)
- Phase 3 — Attack-path analytics and autonomous retesting (complete)
- Phase 4 — Organization-wide policy automation and continuous validation
For a full contributor guide see CONTRIBUTING.md.
make fmt # cargo fmt --all --check
make clippy # cargo clippy --all-targets -- -D warnings
make test # cargo test --lib
make build # cargo build --release
make check # runs all four above in sequenceOr run cargo directly:
cargo fmt --all --check # verify formatting
cargo clippy --all-targets -- -D warnings # lint all targets
cargo test --lib # run library unit tests
cargo build --release # optimized host binaryscripts/deploy.sh (also make deploy) builds, verifies, and packages the
CLI binary for distribution. There is no web service or network call
involved — "deploying" this agent means producing a trustworthy, versioned
release artifact, since it is a local terminal tool:
./scripts/deploy.sh # full gate + build + package
./scripts/deploy.sh --target aarch64-linux-android # cross-compiled package
./scripts/deploy.sh --skip-checks # fast repackage (build + package only)
make deploy # same, via the Makefile
make deploy DEPLOY_FLAGS="--skip-checks" # pass flags throughIt runs CI's required formatting and lint gate exactly (cargo fmt --all --check, cargo clippy --all-targets -- -D warnings -W clippy::pedantic -W clippy::nursery), plus the full cargo test — a deliberate superset of
CI's cargo test --lib, since a release artifact should be verified by at
least as much as CI requires, and the CLI integration suite in
tests/cli.rs exercises the actual compiled binary the way the packaged
archive will be used. It then builds an optimized --release binary
(optionally cross-compiled via --target), and packages it — plus
README.md and LICENSE — into a checksummed
dist/security-agent-<version>-<target-triple>.tar.gz with a matching
.sha256 file (recording the archive's repo-root-relative path, so
sha256sum -c dist/<name>.sha256 verifies correctly from the repo root).
Colors are automatically disabled when not attached to a terminal (or with
--no-color / NO_COLOR), so CI logs stay clean. The script always
operates from the repo root regardless of the caller's working directory.
Pure POSIX-ish bash — no new dependency, consistent with the rest of the
crate.
The console styling deliberately follows the same conventions used across
this org's other launch/verify scripts: a plain colored title (no boxed
banner), light ━━ … ━━ section rules per step, a three-state ✓ (green,
pass) / ✗ (red, fail) / ○ (yellow, skipped) glyph system, and a flat
====...-divided completion block at the end — the same shape those
scripts' own deploy/verify output ends on.
The candle / candle-transformers / tokenizers crates are optional
dependencies grouped under the inference feature flag. They are not used
by the core orchestration logic and are disabled by default:
# Build with the inference back-end enabled
cargo build --release --features inferenceAll skills are compiled into the Rust binary and the tool catalog is generated from the built-in registry. These commands do not use the network or read an external skill source:
./target/release/security-agent
./target/release/security-agent --offline-status
./target/release/security-agent --about
./target/release/security-agent --list-skills
./target/release/security-agent --show-skill security-agent
./target/release/security-agent --show-skill nmap
./target/release/security-agent --list-tools
./target/release/security-agent --run-tool autopsy <local-path>
./target/release/security-agent --run-tool autopsy <local-path> --output <report-path>.txt
./target/release/security-agent --run-tool binwalk <local-blob>
./target/release/security-agent --run-tool foremost <local-blob>
./target/release/security-agent --run-tool bulk_extractor <local-blob>
./target/release/security-agent --run-tool hashdeep <local-path>
./target/release/security-agent --llm-generate <prompt words...>
./target/release/security-agent --llm-perplexity <text words...>
./target/release/security-agent --ask <plain-English instruction...>
./target/release/security-agent --tui--about (alias --version) prints the package version, mission statement,
and the four roadmap phases.
--ask takes a plain-English instruction and routes it to the matching
capability (see Plain-English instructions).
--tui launches an interactive terminal UI over every command above (see
Interactive terminal UI).
src/language_model.rs is a small, from-scratch neural language model
with a vector-quantized, temporal-frequency architecture, trained
deterministically on a security-domain corpus compiled into the binary. The
prediction path is:
- Embed the recent window of tokens into learned vectors — a short multi-channel time signal.
- Self-attend: a single-head scaled dot-product attention layer lets every position in the window mix in every other position's value vector, weighted by a learned, content-dependent query/key match (no causal mask — every position is already-known context for the token being predicted after the window). The attended output is added residually to the raw embeddings, so what each position ends up representing can depend on what's actually in the window, not just where it sits.
- Temporal → frequency: a Discrete Cosine Transform (DCT-II) along the time axis of the attended representation, so the model reasons about how the context changes across the window (its spectral content).
- Residually vector-quantize the spectral features against a stack of
learned codebooks (VQ-VAE style: nearest-code lookup, straight-through
estimator, commitment penalty). Each stage quantizes what the previous
stage could not represent — the final code is the sum of the per-stage
codes (
q = q1 + q2), a residual path around the quantizer that halves the reconstruction error a single codebook leaves behind while keeping the discrete bottleneck. - Predict the next token from the quantized code through a tanh hidden layer and a softmax over the vocabulary.
- Sample: decoding draws from that distribution with temperature and
top-
kfiltering (rather than always taking the most probable token), seeded deterministically from the prompt so the same prompt still always produces the same continuation.
Training is two-phase. SGD (backpropagated by hand, cross-entropy loss)
trains the whole model first; a Levenberg-Marquardt pass then refines
just the self-attention projections against a genuine nonlinear
least-squares objective the model already has lying around — the residual
VQ reconstruction error from step 4 — via a proper Gauss-Newton/trust-region
step (adaptive damping, a gain ratio gating every step, all hand-derived).
Running LM over the whole network isn't feasible here (the dense JᵀJ
it needs would be thousands-by-thousands), so it's scoped to the one
small, well-posed sub-problem where it pays for itself.
The self-attention layer, DCT, residual codebook search, Levenberg-Marquardt solver, and forward/backward passes are all hand-rolled: no external crates, no network, no weights on disk. The model trains itself at startup (around a second) and ships inside the offline binary. Being tiny — and quantized through a discrete bottleneck — its text is modest; it learns the domain vocabulary and local phrasing rather than long-range coherence.
# Continuation of a prompt (temperature/top-k sampling, deterministic per prompt).
./target/release/security-agent --llm-generate the coordinator plans an
# Perplexity: how surprising text is to the model (lower = more in-domain).
./target/release/security-agent --llm-perplexity the policy engine denies scopeThe LanguageModel trait is the seam where a larger model could plug in
later; this is distinct from the still-optional inference feature flag
(below), which is reserved for a heavier candle-based back-end and is not
used by the core.
The same perplexity signal is looped back into the cognitive layer as an
anomaly lens: during a --plan-scan ... --cognitive-review --memory <log> run, every prior finding's text is scored against the model, and text
that does not read like ordinary security-domain English (high perplexity,
or unscorable) is flagged as out-of-domain — a cheap, fully-local check for
encoded payloads, injected markup, or noise stuffed into third-party tool
output. See src/anomaly.rs.
--ask lets the agent understand a plain-English instruction and carry it
out, entirely offline. A grounded intent router (src/nlu.rs) maps the
instruction to one of the agent's real capabilities — report status, list or
explain tools/skills, plan a scan, generate text, or score a string for
anomaly — using two fully-local signals: lexical anchoring against each
capability's trigger vocabulary (and recognition of the agent's own
tool/skill names), plus semantic similarity in the built-in model's learned
embedding space to rank paraphrases. It prints what it understood (intent and
confidence) and a plain-English reply, then runs the action:
./target/release/security-agent --ask "what tools do you have"
./target/release/security-agent --ask "are you healthy and ready"
./target/release/security-agent --ask "explain the nmap skill"
./target/release/security-agent --ask "generate text about scanning targets"
./target/release/security-agent --ask 'is this suspicious: "zzq xqv vfrb qwx"'Routing is scoped to authorized defensive and offensive security work: an
off-topic request with no capability match declines cleanly (out-of-scope)
rather than guessing. And
--ask only executes the read-only, no-authorization intents; anything
that touches an engagement, a persisted log, or authorization (planning a
scan, scheduling a retest, viewing an audit log) is explained — the agent
tells you the exact command to run — but never run through --ask, so plain
English can never widen the agent's authority.
--tui opens a menu- and chat-bar-driven REPL over every command above, all
offline, with no new dependencies (pure std::io):
./target/release/security-agent --tui[1] Offline status [2] About
[3] List tools [4] Show a skill or tool
[5] List skills [6] Run a built-in local tool
[7] Run a real external tool [8] Plan a scan (engagement config)
[9] Record findings (merge) [10] View audit log
[11] Schedule retest [12] Generate text (LLM)
[13] Score text for anomaly (LLM)
[0] Help / full capability summary [q] Quit
Type a menu number to run that function (each prompts for the arguments it
needs, the same ones its CLI flag takes), or just type a plain-English
instruction at the > prompt and press Enter — that's the chat bar,
routed through the exact same grounded router as --ask, including
prompting the built-in language model directly (generate text about ...,
is this suspicious: "..."). Menu option 0 (or typing help) prints the
capability summary page: every function the agent exposes, its CLI
command, and — where the chat bar can run it — a plain-English example.
--tui is a thin wrapper: every menu choice calls the identical command
function the plain CLI dispatches to (src/main.rs), so behavior — including
the offline/online gating from --allow-network — is exactly the same either
way. It reads lines from stdin and exits cleanly at end-of-input, so it is
fully scriptable and tested the same way as the rest of the CLI (see
tests/cli.rs).
Running without arguments is equivalent to --offline-status. To install the
binary into Cargo's local binary directory, run cargo install --path . --locked;
the same commands can then use security-agent instead of the path above.
All 89 tool definitions are stored in and loaded from the binary.
--list-tools also reports whether a corresponding third-party executable is
already present on the local PATH. Catalog presence does not imply that the
third-party executable is installed or functional. Execution plans only
approve tools found locally. Security-Agent does not download, contact, or
silently execute external sources.
Alongside the general security-agent skill, every one of the 89 cataloged
tools has its own skill file under .github/skills/<tool-name>/SKILL.md,
compiled into the binary the same way (--list-skills lists all 90;
--show-skill <tool-name> prints one). Each tool's skill documents:
- its
ExecutionClass(static-local-analysis,active-network, oractive-exploitation— seesrc/registry.rs), - which specialist(s), if any, currently include it in their
approved_toolsscope, - the authorization gate it falls under (
src/policy.rs), and - whether Security-Agent can run it for real today (
--run-external-tool, currently wired forsemgrep,jadx,androguard,apktool,dex2jar, andapksigner) or catalog/detection only (--list-tools).
tool_skills_cover_every_cataloged_tool in src/local_assets.rs asserts
every cataloged tool has a matching skill, so the two stay in sync.
The built-in Autopsy substitute inventories and hashes a local evidence path.
It prints a human-readable report to the terminal, or writes the same report
to a local .txt file when the optional --output argument is supplied.
The built-in Volatility substitute analyzes a local memory image or binary, computes its SHA-256 digest and byte entropy, detects embedded ELF, PE/COFF, and ZIP signatures, and extracts bounded printable strings:
./target/release/security-agent --run-tool volatility <local-memory-image>
./target/release/security-agent --run-tool volatility <local-memory-image> --output <report-path>.txtThe built-in Wireshark substitute strictly parses classic PCAP files, reports capture timestamps and byte totals, and classifies Ethernet, VLAN, IPv4, IPv6, ARP, TCP, UDP, ICMP, and ICMPv6 traffic without live capture:
./target/release/security-agent --run-tool wireshark <local-capture.pcap>
./target/release/security-agent --run-tool wireshark <local-capture.pcap> --output <report-path>.txtFour further forensic substitutes (src/local_analyzers.rs) extend the same
offline, local-file, no-dependency pattern to the file-carving and
feature-extraction family of the catalog:
# Binwalk: map embedded magic signatures and high-entropy (likely
# compressed/encrypted) regions in a firmware image or binary blob.
./target/release/security-agent --run-tool binwalk <local-blob>
# Foremost: carve recoverable embedded files by header, bounding their
# length with a footer where the format defines one.
./target/release/security-agent --run-tool foremost <local-blob>
# Bulk Extractor: pull indicators of compromise — emails, URLs, IPv4
# addresses — out of a blob's printable content.
./target/release/security-agent --run-tool bulk_extractor <local-blob>
# Hashdeep: recursively hash a directory tree (SHA-256 + CRC-32) and report
# sets of files that share a digest.
./target/release/security-agent --run-tool hashdeep <local-path>Each accepts the same optional --output <report-path>.txt. These are
defensive analyzers over evidence you already hold — none contacts a live
target. The offensive (ActiveExploitation) and live-network
(ActiveNetwork) catalog tools are deliberately not reimplemented as
in-house attack code; instead the agent orchestrates the real, installed
binaries under the online opt-in and authorization controls described next.
The runtime is fully offline by default: no command performs live-target
or network activity unless you opt in for that invocation with the explicit
--allow-network flag (src/network_policy.rs, NetworkMode). This makes
going online a deliberate, per-invocation, auditable choice — --offline-status
reports default_network_mode=offline and the online_opt_in_flag.
- Offline (default): only the built-in substitutes and
StaticLocalAnalysistools (local files only) may run. - Online (
--allow-network): the real, installedActiveNetworkandActiveExploitationtools additionally become eligible, so an authorized engagement has full tool scope. Going online never bypasses the authorization policy — when run through a planned scan, target scope, the technique allow-list, deny-lists, approval gates, and the time window are all still enforced.
The agent only ever spawns the real third-party binaries you have installed; it never reimplements a tool's offensive behavior itself. Full-scope active testing is therefore available for authorized work, with the authorization and audit controls kept firmly in place.
Every cataloged tool is classified by ExecutionClass (src/registry.rs):
StaticLocalAnalysis (operates only on local files — semgrep, jadx,
androguard, apktool, dex2jar, apksigner, and others), ActiveNetwork
(scans or contacts a live target), or ActiveExploitation (attempts to
compromise a live target or running process). --run-external-tool
directly invokes a real, locally installed tool. StaticLocalAnalysis
tools run in the default offline mode; live ActiveNetwork /
ActiveExploitation tools require the explicit --allow-network opt-in
placed immediately after --run-external-tool:
# Offline (local files only) — no opt-in needed:
./target/release/security-agent --run-external-tool semgrep --version
./target/release/security-agent --run-external-tool jadx -d <out-dir> <apk-path>
# Online (live target) — requires the explicit opt-in:
./target/release/security-agent --run-external-tool --allow-network nmap -sV <in-scope-host>
./target/release/security-agent --run-external-tool --allow-network sqlmap -u <in-scope-url>The process is spawned with a bounded execution timeout and its stdout,
stderr, exit code, and duration are captured into a report. Arguments given
to --execute/--run-external-tool are trusted as-is. As a non-blocking
aid, arguments to network tools are passed through an intensity advisory
(src/intensity_guard.rs): aggressive flags (-T5, --min-rate,
full-range sweeps) that exceed the engagement's declared max_intensity
print a warning to stderr, but execution still proceeds. Without
--allow-network, a live ActiveNetwork/ActiveExploitation tool is
refused with a message pointing to the opt-in — it never runs active work
in offline mode.
Before spawning any eligible tool, Security-Agent checks the resolved
binary against a bundled integrity manifest (assets/tool_integrity.txt,
compiled into the binary). Each line pins a tool to the expected
lowercase-hex SHA-256 of its executable:
semgrep=<64-hex-sha256-of-the-vetted-semgrep-binary>
Per tool, the check yields one of three states, shown in --list-tools
(the integrity= column) and counted in --offline-status
(integrity_verified_tools=):
- verified — a manifest entry exists and the local binary's SHA-256 matches it. Executes.
- mismatch — a manifest entry exists but the local binary differs. Execution is refused with an error.
- unpinned — no manifest entry. Executes. This is the default for
every tool: the shipped manifest is intentionally empty, so integrity
pinning never blocks day-to-day use until an operator deliberately vets
a binary and adds its hash. Only pinned tools are ever hashed, so an
empty manifest adds no runtime cost. The SHA-256 is the crate's own
implementation (
src/builtin_tools.rs) — no external dependency. Add an entry only with documented provenance for the exact binary you intend to pin.
--plan-scan reads a hand-written engagement configuration file (a plain
key=value text file — see OPERATING_GUIDE.md section 8a for the exact
format), authorizes it through the same PolicyEngine/Coordinator used
by the library's tests, and prints the resulting scan plan:
./target/release/security-agent --plan-scan engagement.txt
./target/release/security-agent --plan-scan engagement.txt --audit-log audit.jsonl
./target/release/security-agent --plan-scan engagement.txt --cognitive-review
./target/release/security-agent --plan-scan engagement.txt --execute <args-passed-to-each-tool>
./target/release/security-agent --plan-scan engagement.txt --findings-log findings.jsonl --execute <args>
./target/release/security-agent --plan-scan engagement.txt \
--cognitive-review --calibration-db calibration.sadb --reasoning-log-db reasoning.sadb
./target/release/security-agent --schedule-retest findings.jsonl
./target/release/security-agent --view-reasoning-log-db reasoning.sadb- With no extra flags,
--plan-scanonly plans: it prints theExecutionPlan(workflow stages, selected toolchain packs, and each task's specialist/techniques/approved tools) or, if authorization failed, the specific reason and a non-zero exit code. --audit-log <path>appends that call's audit records to<path>as an append-only JSON Lines file (src/audit_log.rs), so the audit trail survives past a single run instead of living only in memory.--cognitive-reviewruns both advisory reasoning layers over the resulting plan. First (src/cognition.rs) it prints a risk-yield task ranking, ranked per-target hypotheses about which technique is likely to find what, and a reflective critique flagging coverage gaps (e.g. a task with no locally installed tool). Then (src/cognitive_engine.rs) it prints a full Cognitive Deliberation: an explicit train of thought with provenance links, a Bayesian belief distribution with its uncertainty, the modeled adversary's predicted next moves, attention allocation across targets, and a metacognitive self-assessment that decides whether to escalate to a human. Add--memory <ledger>to make this history-informed (see below); without it the run is stateless and priors are type-based only.--memory <log>loads the append-only findings log at<log>(src/findings_log.rs, viasrc/memory_store.rs) before running--cognitive-review, so cognition reasons from history accumulated across prior engagements: the folded memory boosts hypothesis confidence and attention, and the raw findings drive Bayesian belief revision. A missing log is treated as empty history (no error). Because there is one findings format, a log written by--findings-logis valid--memoryinput directly;--record-findingsmerges logs when needed.--execute <args>additionally runs every approved, locally installed,StaticLocalAnalysis-classified tool in the plan viaexecute_plan, passing<args>to each invocation, and prints each outcome (success with exit code/duration, or the specific failure).--audit-db <path>,--findings-db <path>are drop-in siblings of--audit-log/--findings-log, backed by the zero-dependency.sadbembedded database (see Persisting to.sadbbelow) instead of JSON Lines.--calibration-db <path>(only takes effect with--cognitive-review) loads the accumulated confidence-calibration history from every prior run before this run's hypothesis correction, then appends this run's fresh evidence back — closing the loopCognitiveEngine::with_calibrationexists for but that nothing previously carried forward.--reasoning-log-db <path>(only takes effect with--cognitive-review) archives this run's full Cognitive Deliberation train of thought and metacognitive verdict, for later review with--view-reasoning-log-db.- Flags may be combined, in this order:
--audit-log <path>, then--audit-db <path>, then--cognitive-review, then--memory <log>, then--calibration-db <path>, then--findings-log <path>, then--findings-db <path>, then--reasoning-log-db <path>, then--execute <args>....
The cognitive layers learn from the single append-only findings log. A scan
writes its scored findings with --findings-log; a later engagement reasons
from that accumulated history by pointing --memory at the same file — no
format conversion:
# Engagement 1: run tools and persist scored findings to the log.
./target/release/security-agent --plan-scan engagement.txt \
--findings-log findings.jsonl --execute <args>
# Engagement 2: reason from the accumulated history — sharper hypotheses,
# Bayesian-updated beliefs, higher adversary payoffs, and metacognition that
# no longer flags well-evidenced targets as gaps.
./target/release/security-agent --plan-scan engagement.txt \
--cognitive-review --memory findings.jsonl
# Optional: merge/curate logs (append one log's findings onto another).
./target/release/security-agent --record-findings combined.jsonl findings.jsonlThe log is human-readable (one finding_record per line) and only ever
grows — each engagement's findings accumulate on top of earlier ones, and
cognition is always re-derived by folding the full log.
.sadb is a purpose-built, append-only embedded database (src/sadb.rs)
— a pager, slot-directory heap pages, an immutable-image catalog, and a
checksummed-footer transaction boundary with crash recovery — written
from scratch to keep the crate's zero-external-runtime-dependency
guarantee. It is deliberately not SQLite-compatible: real SQLite's
mutable B-tree file format and trigger/view machinery don't fit either
that guarantee or what this tool actually needs. A .sadb file can only
be read with this agent's own --view-*-db commands (see below) — not
sqlite3, not a generic DB browser. Four flags use it: --audit-db,
--findings-db, --calibration-db, --reasoning-log-db.
Two of the four stores exist purely as alternative storage for data the
JSON Lines flags already persist (--audit-db, --findings-db). The
other two close real gaps that had no JSON Lines equivalent at all:
--calibration-db <path>carriesCognitiveEngine's confidence calibration forward across engagements. Without it,--cognitive-reviewsilently recomputes calibration from scratch on every single run —with_calibrationexists specifically to prevent that, but nothing wired it to persistent storage until this flag did.--reasoning-log-db <path>archives every--cognitive-reviewrun's full train of thought and metacognitive verdict — an immutable, after-the-fact audit trail of why the agent concluded what it did, independent of how the reasoning code itself may change later.
# Engagement 1: review and archive the reasoning, accumulating calibration.
./target/release/security-agent --plan-scan engagement.txt \
--cognitive-review --calibration-db calibration.sadb --reasoning-log-db reasoning.sadb
# Engagement 2: calibration correction now has real cross-engagement
# evidence behind it, and this run's deliberation is archived too.
./target/release/security-agent --plan-scan engagement.txt \
--cognitive-review --calibration-db calibration.sadb --reasoning-log-db reasoning.sadb
# Read any of the four stores back through the CLI:
./target/release/security-agent --view-audit-db audit.sadb
./target/release/security-agent --view-findings-db findings.sadb
./target/release/security-agent --view-calibration-db calibration.sadb
./target/release/security-agent --view-reasoning-log-db reasoning.sadb--view-calibration-db prints the full calibration report (Brier score,
mean calibration error, over/under-confidence tendency, and a
reliability-bin breakdown) that src/calibration.rs has always been able
to compute but that, until this command existed, no CLI path ever
surfaced. Opening a .sadb path that doesn't exist yet creates an empty
database rather than erroring — the same open-or-create ergonomics as the
JSON Lines flags, just for a real page store instead of a text file.