Skip to main content
Nothing in Aspex is a black box. Two builds over the same state are byte-identical, and every conclusion says which of three kinds it is.

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.
Everything downstream of 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 --json on the same configs yields the same attackPaths and blastRadius; aspex lock --no-exec --stdout yields the same lockfile.
  • Live: tool lists come from the servers; aspex lock captures them so a later verify shows exactly which description or schema changed.
  • Scenarios: testdata/corpus/scenarios/*.yaml state truth and expectation for whole environments; aspex scan corpus test runs them. Adding a scenario is how to report a disagreement with Aspex’s reasoning. Corpus →