Nothing reaches a target without passing the scope engine.
The planner only proposes. The scope engine, a separate component in core, allows or refuses. The autonomy level decides who confirms, and the audit log records every step, refused ones included.
Sample flow, fictional lab range. Select a step or let it cycle.
The model asks. The scope engine answers.
Scope is a plain file you write before the first run. A small piece of core code evaluates it for every proposed action. Modules, plugins and the planner never see a way to edit it, so a confused or manipulated model cannot widen its own reach.
Authorized testing only. Run it against systems you own or have written permission to test. Read the rules
enumerate 10.0.0.21allow[0] 10.0.0.0/24allowresolve dc01.corp.acme-demo.exampleallow[1] corp.acme-demo.exampleallowenumerate 10.0.0.13deny[1] 10.0.0.13denyreach 203.0.113.50no allow rule matchesdenychange state on 10.0.0.30autonomy: approve-each-stepaskIllustrative decisions on a fictional lab. Default is deny: no matching allow rule means refused. Every row above, refused ones too, becomes an audit entry.
You can read the whole data path in an afternoon.
A static build with no runtime to install. Copy it to a jump box, point it at an engagement folder, and it works offline. Everything it writes lands in that folder.
- Single binaryStatic build, no interpreter, no container needed. Updating means replacing one file.
- Core is the boundaryScope, graph and scheduler live in core. The agent package imports core. Core never imports the agent.
- PlaybooksRepeatable runs as YAML. Diff them, review them, attach them to the ticket.
- Offline by defaultWith the fallback planner there is no network use beyond your in-scope targets.
Two places to plug in.
Both are narrow on purpose. A plugin adds an action. A planner chooses actions. Neither can change the scope.
Plugins declare what they touch.
A manifest lists hosts, ports, files and mode. The scope engine enforces it at call time, so a plugin that asks for more than it declared is refused. The plugin SDK is not out yet; this is the plan.
name: smb-share-audit needs: hosts: in-scope only ports: [445] mode: read-only writes: [findings] sandbox: wasm # planned
Planners return proposals, nothing more.
The planner reads a view of the graph and a budget, and returns a short list of proposed actions with a reason each. It gets no handle to the network and no write access to the scope.
planner.propose(view: GraphView, budget: Budget) -> list of Proposal Proposal { module, target, reason } # the scope engine decides what happens next
fallbackDeterministic rules. No model, no network.local modelAn endpoint on your own machine or network.hosted modelOnly if you configure one. Receives the graph view you allow.The folder is the product.
No account, no server, no sync. The graph, the evidence and the audit log are ordinary files you can back up, hand over to a client or delete.
- Graph storeAn embedded database in
graph.db. Nodes are hosts, services, identities and findings. Edges say what reaches or grants what. Attack paths are queries over it. - Audit logOne JSON line per step: target, module, time, the decision, the scope rule that decided, and who approved it if anyone did. The tool only appends. It never rewrites or truncates the file.
{"step":14,"action":"enumerate","target":"10.0.0.21","decision":"allow","rule":"allow[0]","by":"scope-engine"}
{"step":15,"action":"enumerate","target":"10.0.0.13","decision":"deny","rule":"deny[1]","by":"scope-engine"}
{"step":16,"action":"state-change","target":"10.0.0.30","decision":"approve","rule":"approve-each-step","by":"operator"}
No telemetry, and the egress list is short.
your targetsOnly hosts that pass the scope engine.a model endpointOnly if you configure one. Off by default.everything elseNothing. No analytics, no update ping, no crash reports.Rules we hold the design to.
Policy outside the modelAnything that must always hold is enforced in code the model cannot reach.Deny by defaultIf no rule allows an action, it does not happen.Files over servicesState is a folder you can read, copy and delete.Log before and afterRefusals are entries too. The record is the product.Narrow extension pointsPlugins and planners get a small surface and a declared reach.Small enough to auditIf a piece cannot be reviewed in an afternoon, it is too big.