Threat model (MITRE ATLAS)
This is Themis's own threat model, written with MITRE ATLAS. It lists what Themis protects, where trust changes, which ATLAS techniques apply, what the code does about each one, and what remains open. It is informational and is not a certification. The OWASP and NIST mappings in the compliance set are the design mappings shown to reviewers; this page is the threat model they sit next to.
Source and version: ATLAS data version 2026.09 (modified 2026-09-15), read from MITRE's official data repository at https://github.com/mitre-atlas/atlas-data (file dist/v6/ATLAS-2026.09.yaml, tag v2026.09), retrieved 2026-10-11. This is the same version that the Aegis mitre-atlas skill was corrected against and that scripts/check-atlas-ids.js checks. The https://atlas.mitre.org site was also reached on 2026-10-11, but its pages did not return a readable technique list, so the repository data is the source of every ID and name below. Tactic names are the 2026.09 names: Reconnaissance (AML.TA0002), Resource Development (AML.TA0003), Initial Access (AML.TA0004), AI Model Access (AML.TA0000), Execution (AML.TA0005), Persistence (AML.TA0006), Privilege Escalation (AML.TA0012), Defense Evasion (AML.TA0007), Credential Access (AML.TA0013), Discovery (AML.TA0008), Lateral Movement (AML.TA0015), Collection (AML.TA0009), AI Attack Adaptation (AML.TA0001), Command and Control (AML.TA0014), Exfiltration (AML.TA0010), Impact (AML.TA0011).
Assets
| Asset | Why it matters |
|---|---|
| Approval decisions | They are the only gate between a model's proposal and a write or execute action |
The audit log and run state in ~/.themis/themis.db |
Evidence of what the agent did |
| Credentials and tokens for external MCP servers, and secrets in task text | Disclosure would give an attacker access elsewhere |
| Reports and findings | Users act on them |
| Skill content (Aegis) | It shapes what a model is told to do |
Trust boundaries
- Host AI client and the Themis plugin (Mode 1). The model on the host is untrusted for decisions: it can propose and cannot approve. The host's elicitation prompt, answered by a person, is the approval channel.
- Dashboard and browser (Mode 2). The dashboard listens on 127.0.0.1, needs a per-launch session token, checks Host and Origin, and sends a strict Content-Security-Policy and no CORS headers.
- Gateway and external MCP servers. Everything an external server returns is untrusted data. Servers are reachable only by the skills that list them, and write or execute tools appear only if the server opted in.
- Aegis content supply chain. Skill methodology is written text under version control. Intel blocks are committed from the maintainer's machine, so the maintainer's workstation and the feeds it reads are inside the trust boundary. Content is updated monthly.
- Hosted Aegis MCP. A stateless, read-only endpoint that serves public skill text. It has no model call, no database and no credentials.
Threats, mitigations and gaps
"Tactic" shows an ATLAS tactic only where a published ATLAS case study in the 2026.09 data pairs that technique with that tactic. Where the data does not pair them, the cell says so rather than guessing.
| ID | Risk | Themis control | Code path (file:symbol) | Test | Residual / gap |
|---|---|---|---|---|---|
| T1 | Prompt injection through tool output: AML.T0051 LLM Prompt Injection, sub-technique AML.T0051.001 Indirect (tactic Execution, AML.TA0005) | Tool output is secret-redacted, cut at 4000 characters and wrapped as untrusted data; closing-tag sequences inside the output are neutralised before wrapping | packages/themis-gateway/src/gateway.ts:wrapUntrusted, packages/themis-core/src/secrets.ts:redactSecrets |
packages/themis-gateway/test/wrapper-breakout.test.ts |
GAP: tool descriptions from connected servers are not wrapped. (The closing-tag breakout is closed by neutraliseWrapperTags.) Wrapping reduces the risk and does not guarantee a model ignores injected instructions. Existing coverage: packages/themis-gateway/test/gateway.test.ts ("runs read tools and wraps output as untrusted"). |
| T2 | Unauthorized tool execution: AML.T0053 AI Agent Tool Invocation (tactics Execution AML.TA0005, Privilege Escalation AML.TA0012, Lateral Movement AML.TA0015) | Default-deny per-skill allowlist; deterministic read/write/execute classification; write and execute are proposals only | packages/themis-core/src/mcp/config.ts:serversForSkill, packages/themis-core/src/mcp/tool-policy.ts:classifyTool, packages/themis-gateway/src/gateway.ts:createGateway |
packages/themis-core/test/mcp/governance.test.ts ("returns nothing for a skill no server lists (default-deny)"), packages/themis-gateway/test/gateway.test.ts ("turns write/execute calls into pending approval requests — never executed") |
A read-classified tool on a connected server can still return harmful data. Tools connected directly to your assistant in plugin mode bypass Themis. |
| T3 | Model-driven approval bypass: AML.T0053 AI Agent Tool Invocation used to push an action through | Only a human decision can approve; canExecuteApproval rejects anything not approved by a human; approval is single-use and bound to the run; a script limits the files that may call the deciding function |
packages/themis-core/src/approvals.ts:canExecuteApproval, packages/themis-plugin/src/approval.ts:decideFromHuman, packages/themis-app/src/server/routes/approvals.ts:registerApprovalRoutes, scripts/check-deps-themis.js (APPROVAL_DECIDERS) |
packages/themis-plugin/test/approval-invariant.test.ts ("model-supplied arguments cannot approve: no tool takes an approval decision"), packages/themis-gateway/test/approval-invariant.test.ts ("refuses an "approved" record that no human decided (tampered store)"), packages/themis-app/__tests__/server/approvals.test.ts ("no model-reachable tool can decide an approval") |
A person can still approve without reading. The model writes the reason text shown with the request; it is redacted and capped at 1000 characters but can be persuasive. |
| T4 | Malicious or compromised tool server: AML.T0010.005 AI Agent Tool (AI Supply Chain Compromise, Initial Access AML.TA0004); AML.T0099 AI Agent Tool Data Poisoning (tactic not paired in the data) | Servers are opt-in per skill; unreachable servers degrade to no tools; output is untrusted data; calls are budgeted and audited | packages/themis-core/src/mcp/config.ts:loadMcpServers, packages/themis-gateway/src/gateway.ts:createGateway |
packages/themis-core/test/mcp/governance.test.ts ("drops entries with invalid id, transport or url"), packages/themis-gateway/test/gateway.test.ts ("enforces the per-server call budget") |
GAP: tool descriptions from a connected server reach the model unmodified, so a malicious server can try to steer the model through them. Connect only servers you trust. |
| T5 | Secret disclosure to the model or into logs: AML.T0057 LLM Data Leakage (tactic Exfiltration, AML.TA0010); AML.T0085.001 AI Agent Tools (tactic Collection, AML.TA0009); AML.T0098 AI Agent Tool Credential Harvesting (tactic Credential Access, AML.TA0013) | Secret and email redaction on arguments, results, approvals, audit data, findings and reports; secrets in a finding force BLOCK before any model sees it | packages/themis-core/src/secrets.ts:redactSecrets, packages/themis-core/src/redact.ts:redactDeep, packages/themis-core/src/guardrail.ts:precheckSecrets |
packages/themis-core/test/secrets.test.ts ("redacts multiple secrets in same string"), packages/themis-core/test/guardrail.test.ts ("precheck passes clean findings to the model (null) and force-BLOCKs secrets") |
Redaction is pattern based. In standalone mode your task text goes to the model provider you choose. The .env key file is mode 0600 on macOS and Linux only. |
| T6 | Resource exhaustion and runaway loops: AML.T0034.002 Agentic Resource Consumption (tactic not paired in the data); AML.T0029 Denial of AI Service (tactic Impact, AML.TA0011) | Per-server call budget and timeout with hard caps, output cap, plan capped at MAX_SUBTASKS, request body caps |
packages/themis-gateway/src/gateway.ts:createGateway, packages/themis-core/src/mcp/config.ts:loadMcpServers, packages/themis-core/src/planning.ts:MAX_SUBTASKS, apps/web/app/api/mcp/route.ts:MAX_BODY_BYTES |
packages/themis-gateway/test/gateway.test.ts ("enforces the per-server call budget"), packages/themis-core/test/planning.test.ts ("caps the plan at MAX_SUBTASKS") |
GAP: the hosted MCP route has only a best-effort per-client limit (apps/web/lib/rate-limit.ts, 120 requests a minute per client IP, Anthropic's published outbound range exempt; tested in apps/web/__tests__/rate-limit.test.ts). It lives in the memory of one server instance, so on serverless hosting each instance counts separately and it is not a hard quota. It trusts the first hop of x-forwarded-for, which Vercel overwrites; on other hosts a client could set that header itself. |
| T7 | Poisoned run context or earlier findings feeding later steps: AML.T0080 AI Agent Context Poisoning (tactic not paired in the data) | Context validated and size-limited; fixed workflow order; BLOCKed findings excluded from the report | packages/themis-core/src/sanitise.ts:validateContext, packages/themis-core/src/workflow.ts:advance, packages/themis-core/src/guardrail.ts:synthesisableResults |
packages/themis-core/test/workflow.test.ts ("fanout rejects results for sub-tasks that are not ready, leaving the run retryable"), packages/themis-core/test/guardrail.test.ts ("synthesis excludes BLOCKed results") |
GAP: subtly false content in an earlier finding is not detected by code; the guardrail verdict is model produced. |
| T8 | Poisoned Aegis content or intel: AML.T0010.001 AI Software (AI Supply Chain Compromise, Initial Access AML.TA0004) | Skill content is reviewed text under version control; skill lint checks the format; dependency allowlists limit what each package may import | packages/aegis/skills/, scripts/lint-skills.js, scripts/check-deps.js, scripts/check-deps-themis.js |
scripts/tests/lint-skills.test.js, scripts/tests/check-deps.test.js |
GAP: intel is committed from the maintainer's machine and not independently verified; the maintainer and the feeds read are trust assumptions. Release provenance and exact-version publishing are Phase 7 work and are not claimed. |
| T9 | Local dashboard abuse (a web page or local process driving the dashboard): AML.T0053 AI Agent Tool Invocation reached through the UI | Loopback bind, per-launch session token in an HttpOnly SameSite=Strict cookie, exact Host allowlist, same-origin checks on state-changing requests, 64 KB body cap, CSP, no CORS | packages/themis-app/src/server/security.ts:checkHost, packages/themis-app/src/server/security.ts:checkSession, packages/themis-app/src/server/security.ts:checkOrigin |
packages/themis-app/__tests__/server/security.test.ts ("checkHost rejects other hosts, other ports and a missing Host", "sessionCookie is HttpOnly, SameSite=Strict, host-only"), packages/themis-app/__tests__/guards.test.ts ("never sets an Access-Control- header in the server") |
The session token protects one local launch and is not user authentication; another process of the same operating-system user can read local files. |
| T10 | Tampering with the audit trail, or acting without leaving one | Append-only audit table enforced in the database; a failed audit write fails the tool call | packages/themis-core/src/store/sqlite.ts (audit_events), packages/themis-gateway/src/gateway.ts:createGateway |
packages/themis-core/test/store.test.ts ("makes audit_events append-only at the database level"), packages/themis-gateway/test/gateway.test.ts ("fails closed when the audit log cannot be written") |
Someone with file access can replace or delete the database file itself; the log is not signed. |
| T11 | Hosted MCP used to write, run or reach other systems | All three tools are read-only and serve public skill text; the route is stateless, caps the body at 64 KB and sets no-store and anti-framing headers; skill names are validated against a strict pattern and phase files stay inside the skills directory | packages/aegis/mcp/server.js:createAegisMcpServer, apps/web/app/api/mcp/route.ts:handle |
packages/aegis/tests/mcp-server.test.js ("advertises exactly the three read-only tools", "rejects a path-traversal skill name at the schema boundary"), apps/web/tests/guard/no-model-deps.test.js |
The endpoint is unauthenticated by design. Reachability and rate limiting are covered in T6. |
ATLAS techniques not addressed
Themis does not train, host or fine-tune a model, so training-time techniques such as AML.T0020 Training Data Poisoning and AML.T0018 Manipulate AI Model apply to the model provider, not to Themis. It has no retrieval index, so RAG-specific techniques do not apply either. If retrieval or persistent agent memory is added, this page must be revisited.
To report a weakness in any control, see SECURITY.md.