The three kinds of statement
A path never claims it was walked. An observation never claims intent. Keeping these apart is the whole design. Capabilities & attack paths → · Observed vs inferred →
The environment
An Environment (internal/agentenv) is the normalized state of one machine’s agent setup: agents (clients), MCP servers with their tools, lifecycle hooks, skills, instruction files, and what follows from them: fingerprints, derived resources, destinations, attack paths and the blast radius.
agentenv consumes the same model, so a capability reads the same in a lockfile, a PR comment, an explain answer and the MCP tool.
The trust boundary
The boundary Aspex reasons about is the agent’s context. Anything that enters it (a prompt, a pasted document, a fetched page, an issue body, a tool result) can carry an instruction; anything the agent can do, an instruction can ask for. This is why the first hop of every attack path is “instruction from a prompt, document, or tool result”, and why ingress capabilities matter: they widen who can write into the context.Persistence
An agent’s own configuration, hooks, skills, instruction files and memory are what future sessions trust, so writes to them are first-class. A writable root is resolved to the agent-state files it reaches (~/.claude.json, .mcp.json, ~/.claude/settings.json hooks, CLAUDE.md, .cursorrules, memory, shell startup files) and whether writing them executes code at the next session start. AP003 covers ingress plus such a write; MCP200 flags the writable half alone; aspex scan hooks judges the commands hooks run; lock / verify detect any change.
Change
agentenv.Compare(before, after) classifies each change as informational, security-relevant or suspicious, based on content (the injection patterns from rules.ClassifyText) and on capability deltas, and reports attack paths added or removed and blast radius before and after. A tool-description change is security-significant even when the executable did not change; that is the rug-pull case. Change detection →
Reproducing a finding
- Static:
aspex scan --no-exec --jsonon the same configs yields the sameattackPathsandblastRadius;aspex lock --no-exec --stdoutyields the same lockfile. - Live: tool lists come from the servers;
aspex lockcaptures them so a laterverifyshows exactly which description or schema changed. - Scenarios:
testdata/corpus/scenarios/*.yamlstate truth and expectation for whole environments;aspex scan corpus testruns them. Adding a scenario is how to report a disagreement with Aspex’s reasoning. Corpus →