63 lines
3.3 KiB
Markdown
63 lines
3.3 KiB
Markdown
# Threat Model
|
|
|
|
## Assets
|
|
|
|
- Authentik tokens and service identities;
|
|
- connector credentials;
|
|
- project source and documentation;
|
|
- container metadata and logs;
|
|
- Docker socket access;
|
|
- policy and client bindings;
|
|
- audit integrity;
|
|
- gateway configuration;
|
|
- backup material.
|
|
|
|
## Trust boundaries
|
|
|
|
1. external MCP client to NPM/router;
|
|
2. browser to web/control API;
|
|
3. control plane to Authentik;
|
|
4. router/control plane to ContextForge;
|
|
5. ContextForge to connectors;
|
|
6. connector to target system;
|
|
7. Docker broker to Docker socket;
|
|
8. services to PostgreSQL/Redis;
|
|
9. backup process to storage.
|
|
|
|
## Primary threats and controls
|
|
|
|
| Threat | Example | Required controls |
|
|
|---|---|---|
|
|
| Token substitution | token issued for another API reused at MCP endpoint | issuer, audience, expiry, signature, resource validation |
|
|
| Confused deputy | connector called with a target from another project | connector-side project/resource allowlist |
|
|
| Tool poisoning | malicious description or output tries to alter agent behavior | managed manifests, sanitize metadata, treat content as data |
|
|
| Prompt injection | README tells agent to reveal secrets | never authorize from content; explicit tool policies |
|
|
| SSRF | connector endpoint points to metadata service | registered endpoints, URL parser, private-range policy, no arbitrary URL |
|
|
| Path traversal | `../../secrets` in resource URI | canonical path and root containment checks |
|
|
| Command injection | container name placed into shell command | no shell; structured Docker SDK calls |
|
|
| Excessive data exfiltration | huge log/file response | pagination, byte/row/time limits, redaction |
|
|
| Secret leakage | token appears in logs/tool output | structured logging, secret scanners, redaction profiles |
|
|
| Approval replay | old operation approval reused | plan hash, actor, target, expiry, single-use state |
|
|
| Audit tampering | operator deletes incriminating event | append semantics, restricted DB role, export/retention |
|
|
| Supply-chain compromise | mutable `latest` image changes | exact tags/digests, SBOM, scans, update gate |
|
|
| DoS | expensive repeated search/log calls | per-client rate limit, timeouts, concurrency caps |
|
|
| Cross-project cache bleed | cached result returned to wrong project | project/environment/client in cache key |
|
|
| Docker breakout | compromised broker abuses socket | minimal API, read-only logic, network isolation, no arbitrary labels/exec |
|
|
|
|
## Abuse cases to test
|
|
|
|
- a VacatureRadar token requests a Ludarium endpoint;
|
|
- a production-observer client invokes an unbound write name;
|
|
- a document path escapes its registered root through symlinks;
|
|
- a Gitea file contains a fake token and malicious instructions;
|
|
- Docker logs contain an Authorization header;
|
|
- an unknown alias attempts to proxy to an attacker-controlled URL;
|
|
- a revoked client reuses a cached token;
|
|
- ContextForge returns a tool not present in the desired catalog;
|
|
- Redis is flushed during reconciliation;
|
|
- a connector returns more than the output budget.
|
|
|
|
|
|
## WP-160 implementation notes
|
|
|
|
The Gitea and MCP dataplane URL contracts reject localhost, metadata hostnames, and private, loopback, link-local, reserved, unspecified, or multicast IP literals. Redirects remain same-origin and bounded. Repository test fixtures may contain deliberately fake secret-like values; the security scan classifies those paths as fixture placeholders and fails on non-fixture findings. |