AKOS threat model
Assets: credential values (keychain), research provenance integrity (executions, evidence, audit chain), the registry (contracts, clients), the node and LAN (SSRF pivot), the shared tunnel (other MacLustr sites).
| # | Threat | Control | Test |
|---|---|---|---|
| T1 | Credential leakage into DB, logs, exports, generated code, UI | Values only in keychain; DB stores vault:// refs; akos/vault/redact.py scrubs every active secret value from log records and HTTP responses; generated clients read AKOS_CRED_<NAME> env vars; tests grep DB dump, logs, export zips, repo for fake secret |
tests/security/test_secret_leakage.py |
| T2 | SSRF / internal network access via discovery or execute | akos/gateway/ssrf.py: resolve host, reject loopback, link-local (169.254/16 incl. cloud metadata), RFC1918, ULA, multicast, 0.0.0.0, .local; re-check after redirects (httpx follow_redirects=False, manual bounded redirect loop re-validating); DNS rebinding mitigated by pinning the resolved IP for the connection (httpx transport with local resolver) |
tests/security/test_ssrf.py |
| T3 | Prompt injection from retrieved documentation | Docs are stored as evidence text, never executed; archaeologist only parses OpenAPI/JSON structurally; UI renders docs as escaped text; generated code comes from templates, never from doc content (doc strings are escaped) | tests/security/test_prompt_injection.py |
| T4 | Unsafe generated code | Codegen from fixed templates + AST static scan (akos/compiler/scan.py: no eval/exec/subprocess/os.system, only allowed imports); tests run under sandbox-exec |
tests/unit/test_codegen_scan.py |
| T5 | Bypass of the enforcement boundary | Worker sandbox profile denies all outbound network except loopback; proxy allows only hosts in live egress_grants; attempts logged as blocked; unmanaged routes documented and labelled unobserved |
tests/security/test_enforcement.py (live on node) |
| T6 | Auth bypass, privilege escalation, tenant crossing | argon2id, constant-time token compare on sha256, role checks per route, project-bound tokens cannot read other projects' executions/datasets | tests/security/test_authz.py |
| T7 | Audit tampering | Hash chain (prev_hash, hash) verified by GET /audit/verify; append-only (no UPDATE/DELETE grants on the table from the app role would need a second role — v1: application never updates audit rows; trigger forbids UPDATE/DELETE) |
tests/unit/test_audit_chain.py |
| T8 | Resource exhaustion | Rate limit per token/IP, request body limit, execution timeout, max response size, bounded worker concurrency, per-project budgets | tests/security/test_rate_limit.py |
| T9 | Path traversal in artifact/export downloads | Artifacts addressed by sha256 only; export filenames validated against a whitelist | tests/security/test_paths.py |
| T10 | Dependency integrity | uv.lock + pnpm-lock.yaml pinned; uv sync --frozen in deploy hook |
deploy hook |
| T11 | Disruption of other tunnel sites | Only an additive Caddy route via mld; app never touches Caddy directly |
manual review |
| T12 | Idempotency / duplicate executions on retry | idempotency_key unique on executions and jobs |
tests/integration/test_idempotency.py |
Out of scope / accepted: physical access to the node; a user with SSH on the node can read the keychain (same trust domain as the existing apps); Claude Code hooks are advisory.