Security Model
Purpose #
Summarise aidokit's threat model, trust boundaries, and the mitigations the architecture enforces. Authoritative long-form lives in .docs/docs/specs/security-model.md; user-facing policy lives in SECURITY.md.
Big Picture #
aidokit is closer to cookiecutter than to "an AI service in the cloud" — it writes files locally and runs declared shell commands. The threat surface is code that writes files and runs shell commands on the user's machine.
Five guiding principles, from .docs/docs/specs/security-model.md §3:
- Defense in depth. Capability declarations + conformance harness + signed packages + dry-run + audit log all overlap.
- Fail closed. Unknown trigger → don't suggest. Missing install spec → refuse install. Manifest tampering → refuse to use.
- Honest disclosure. Capabilities must be declared truthfully. Misdeclaration is a conformance violation.
- No magic, no surprises.
--dry-run, audit log, no background activity, no phone-home. - Authority over identity. Trust flows from verified capability (conformance + signing), not from organisational claims.
How It Works #
Trust boundaries #
From .docs/docs/specs/security-model.md §5:
| Boundary | Trust | Mitigation |
|---|---|---|
| User's machine | trusted | (the user already runs code there) |
| Project directory | scoped | adapters write only declared paths |
| User's home directory | limited | only $AIDO_HOME (default ~/.aido/) writes; never dotfiles or creds |
First-party @aidokit/* packages |
trusted (verifiable) | npm provenance from v1.0; npm audit signatures |
| Third-party adapters / stack packs | untrusted by default | conformance CI + capability declarations + signing as trust signals |
| MCP servers (catalog, non-sensitive) | scoped | securitySensitive flag for elevated capability |
| MCP servers (catalog, sensitive) | gated | non-bypassable confirmation, never --yes-bypass |
MCP servers (custom via --custom-url) |
explicitly untrusted | forced confirmation; source: 'custom' in audit log |
| npm registry | relied upon | pinned versions, lockfile, provenance verification |
| User's AI coding CLI (Claude Code, Codex, …) | trusted (user-chosen) | aidokit only writes config; never runs the model |
Threat model (abridged) #
Full table at .docs/docs/specs/security-model.md §6.1. High-severity threats and primary mitigations:
| Threat | Mitigation |
|---|---|
Malicious adapter writes outside declared writesPaths |
Capability declaration + conformance harness + path validation |
Malicious adapter executes undeclared shell commands in postInstall |
Capability declaration + conformance review |
Malicious stack pack writes files directly via Node fs |
Stack packs MUST NOT emit files — cardinal rule + harness |
| Compromised npm package replaces a first-party adapter | npm provenance (v1.0); lockfile integrity |
| Supply-chain attack via transitive dep | pnpm strict mode; pinned exact versions; dep review |
Tampering with .aido/adapter.md to claim higher conformance |
aidokit doctor re-verification; conformance snapshot |
--yes bypassing safety confirmations |
securitySensitive and custom MCPs cannot be bypassed |
aidokit sync overwriting user-customised files silently |
Diff preview required; syncOverwritePolicy: 'on-confirm' |
Out-of-scope threats include OS-level privilege escalation, network MITM (TLS assumed), and compromise of the user's AI coding CLI.
Mitigations summary #
From .docs/docs/specs/security-model.md §7:
- Capability declarations — adapter manifests list
writesPaths,runsShellCommands,networkCalls; AD-STD-CAP-01 conformance check cross-references actual imports + call sites against declarations (CHANGELOG[Unreleased]). - Conformance harness — runtime verification of all spec MUSTs (see conformance-levels.md).
- Signed packages (v1.0+) —
npm publish --provenance --access public; users verify withnpm audit signatures. - Dry-run mode —
--dry-runoninitandsyncwrites nothing. - Staged writes —
<projectRoot>/.aido-staging/; atomic rename on success. - Audit log —
<projectRoot>/.aido/state.jsonrecords every MCP install, includinguserConfirmedandsource: 'catalog' | 'custom'. securitySensitiveis non-bypassable —--yesdoes not skip the confirmation.- No auto-install of prereqs — ADR-0008.
- No telemetry — zero network calls from
aidokititself (excluding npm install). - Reserved namespaces —
@aidokit/*scope owned by core team.
What v1.0 adds over v0.5 #
From .docs/ROADMAP.md §v1.0 and CHANGELOG [Unreleased]:
- Signed npm packages (Sigstore / npm provenance) for every
@aidokit/*package — see wiki/supply-chain/signed-packages.md. capabilitiesfield onAdapterManifest(separate from existingcapabilityDeclarations) for v1.0 supply-chain hardening.- AD-STD-CAP-01 conformance check verifies declared capabilities match the adapter's actual source.
.aidokit/capabilities.jsonartifact (Strict tier only) — emitted by the CLI from every declared adapter'smanifest.capabilities. See ADR-0017 for the design and wiki/reference/adapter-capabilities.md for the per-adapter table.aidokit verify --capabilities(D4) — regex-based static cross-check between the artifact and the emitted hook scripts. Reports undeclared shell commands / network hosts /setIntervalas warnings.aidokit manifest --verify-capabilities(D6) — same verifier surfaced through the manifest command, exits non-zero on drift.aidokit audit export --format soc2|eu-ai-act(C5+C6) — packages capabilities + ADRs + change summaries + blockers into an evidence packet. Mapping docs at docs/compliance/soc2.md and docs/compliance/eu-ai-act.md.- Local-only MetricsLog (
AIDOKIT_METRICS=1) — JSONL of scope violations, context reloads, task lifecycle, token estimates. Read withaidokit metrics summary. Local-first, never transmitted. See wiki/privacy/index.md. SECURITY.mdat the repo root with reporting contact (george@aicenter.ae), 90-day coordinated disclosure window, per-version policy, capability boundaries, and supply-chain notes.
Example: aidokit mcp add filesystem (security-sensitive) #
$ aidokit mcp add filesystem --yes
⚠ Security-sensitive MCP
Filesystem MCP can write or delete files outside the engine directory.
--yes does NOT bypass this confirmation.
Roles to scope: (none — manual choice required for sensitive entries)
? Proceed? (y/N) n
ℹ Cancelled. No changes made.
If confirmed, the audit log records userConfirmed: true and source: 'catalog'.
Diagram #
%%{init: {
"theme": "base",
"themeVariables": {
"fontFamily": "ui-sans-serif, system-ui, -apple-system, Segoe UI, sans-serif",
"fontSize": "14px",
"primaryColor": "#eff6ff",
"primaryTextColor": "#0f172a",
"primaryBorderColor": "#2563eb",
"lineColor": "#475569",
"secondaryColor": "#f1f5f9",
"tertiaryColor": "#ffffff",
"clusterBkg": "#f8fafc",
"clusterBorder": "#cbd5e1"
}
}}%%
flowchart LR
classDef actor fill:#ede9fe,stroke:#6d28d9,color:#1e1b4b,stroke-width:1.2px;
classDef cli fill:#dbeafe,stroke:#1d4ed8,color:#0c1f4a,stroke-width:1.4px;
classDef adapter fill:#cffafe,stroke:#0e7490,color:#083344;
classDef pack fill:#dcfce7,stroke:#15803d,color:#052e16;
classDef core fill:#fef9c3,stroke:#a16207,color:#422006;
classDef artifact fill:#f1f5f9,stroke:#475569,color:#0f172a;
classDef stop fill:#fee2e2,stroke:#b91c1c,color:#7f1d1d,stroke-dasharray:4 3;
classDef ok fill:#ecfdf5,stroke:#047857,color:#064e3b;
classDef external fill:#fff7ed,stroke:#c2410c,color:#431407;
user["User runs aidokit"]:::actor --> cli["@aidokit/cli"]:::cli
cli --> manifest["adapter.manifest.capabilityDeclarations"]:::core
manifest --> harness{"Conformance check"}:::stop
harness -->|verifies emissions vs declarations| pass["✔"]:::ok
harness -->|misdeclaration| fail["✘ block publish"]:::stop
cli --> staging[".aido-staging/ (atomic)"]:::artifact
cli --> audit[".aido/state.json"]:::artifact
cli --> sens{"MCP securitySensitive?"}:::stop
sens -->|yes| confirm["explicit confirm (no --yes bypass)"]:::stop
sens -->|no| auto["scope per suggestedFor"]:::ok
Common Mistakes #
- Bypassing the staging dir by writing directly from an adapter. Adapters return data; the CLI writes. See ADR-0005 §4.
- Setting
securitySensitive: falsefor an MCP that meets the sensitive criteria (mcp-catalog §10.1). - Adding
child_processusage in an adapter without declaringshellCommands. AD-STD-CAP-01 will catch the mismatch. - Phoning home for "version-check" pings. Zero network calls from
aidokititself. Period. See .docs/docs/specs/security-model.md §7.9.
Checklist #
For any change that touches IO or shell execution:
- [ ]
writesPaths/runsShellCommands/networkCallsin the adapter manifest cover every new path/command/endpoint. - [ ] AD-STD-CAP-01 conformance check passes (declarations match actual code).
- [ ] If adding an MCP entry:
securitySensitivereflects reality. - [ ] If your code adds a new prompt: confirm whether
--yesshould bypass; if it must not (sensitive), implementbypassYes: trueper ADR-0007 §6.