Security Model¶
Doable's security posture is built on defense in depth. The same dangerous capability β running AI-generated code on your server β is wrapped by five independent layers, any one of which would block a typical attack.
Trust boundaries¶
ββββββββββββββββββββββββββββββββββ
PUBLIC INTERNET βββΆβ nginx / Caddy (TLS, rate-limit)β
βββββββββββββββββββ¬βββββββββββββββ
β
ββββββββββββββββββββββββΌββββββββββββββββββββββ
β 127.0.0.1 only β TRUSTED HOST β
β β
β βββββββ βββββββ βββββββ β
β β web β β api β β ws β app procs β
β ββββ¬βββ ββββ¬βββ ββββ¬βββ β
β β β β β
β β ββββββ΄βββββ β β
β β βpostgres β β β
β β βββββββββββ β β
β β β
β β ββββββββββββββββββββββββββ β
β ββββΆβ docore worker process β β
β β (sandbox + isolator) β β
β ββββββββββββ¬ββββββββββββββ β
β β β
β ββββββββββΌββββββββββ β
β β dovault jail β per-project β
β β (FS + cgroups) β β
β ββββββββββ¬ββββββββββ β
β β β
β ββββββββββΌββββββββββ β
β β project files + β β
β β Vite dev server β β
β ββββββββββββββββββββ β
ββββββββββββββββββββββββββββββββββββββββββββββββββ
The five layers¶
| # | Layer | What it protects against |
|---|---|---|
| 1 | TLS proxy (nginx/Caddy) | Eavesdropping, DDoS at L7, basic abuse |
| 2 | JWT auth + role checks | Unauthorized access to API endpoints |
| 3 | Tool/policy sandbox (docore) |
The AI calling tools it shouldn't (rm -rf, fetch from attacker URL) |
| 4 | Process isolation (docore isolator) |
A compromised AI worker affecting other workers / the API process |
| 5 | Runtime jail (dovault) |
Spawned project processes (Vite, npm scripts) escaping their project root or starving the host |
Each layer assumes the previous one might fail. That's the point.
Specific threats and how they're addressed¶
"The AI deletes /etc/passwd"¶
- Policy denies
rmoutright viaDEFAULT_DANGEROUS_COMMANDS. - Sandbox rejects the call before execution, even if the model produces it.
dovaultjail rejects writes outside the project root at the OS level.
"The AI exfiltrates code to an attacker's URL"¶
- URL allow-list in policy (
DEFAULT_URL_ALLOWLIST) blocks fetches outside known package registries / docs sites. - Audit log records every attempted fetch β admins see them.
"Generated code includes a malicious npm package"¶
pnpm installruns inside thedovaultjail with no network access beyond the registry allow-list.postinstallscripts execute with the same Node permission model β they can't read outside the project, can't fork unrelated processes, can't exhaust memory.
"A user runs an infinite loop in their Vite dev server"¶
- Resource limits (cgroups on Linux, Job Object on Windows) cap each project at e.g. 150 MB / 30% CPU.
- The OS kills the process when limits are exceeded; the host stays healthy.
"Stolen JWT"¶
- Short access-token TTL (default 15 minutes).
- Refresh tokens in HttpOnly cookies (immune to XSS).
- Stateless tokens β rotating
JWT_SECRETinvalidates everything at once.
"Compromised OAuth/integration token"¶
- Stored encrypted with
ENCRYPTION_KEY(AES-256-GCM). - Per-tool revocation from the audit panel.
- Rotating
ENCRYPTION_KEYinvalidates all stored tokens.
"Cross-tenant data leak"¶
- Every query in
packages/db/src/queries/is scoped by workspace ID. - Middleware enforces workspace membership before route handlers run.
- Project filesystems live in distinct directories under
PROJECTS_ROOT/; the jail prevents traversal.
Things Doable does NOT do¶
- No automatic dependency vulnerability scanning β bring your own (Snyk, Dependabot).
- No automatic AI prompt-injection defense beyond the sandbox layers β adversarial users can craft prompts that try to trick the agent into denied behavior. The sandbox catches the resulting tool calls; the model itself isn't hardened.
- No outbound egress firewall by default β if you accept untrusted user projects, run the host on a network with default-deny egress.