Veil Threat Model
May 20, 2026 · View on GitHub
Veil sits between AI coding agents and the network. It hides real Bearer secrets behind format-preserving placeholders, stores the real values in an encrypted per-project vault, and runs a local MITM proxy that swaps placeholders for real credentials on outbound HTTPS requests.
This document describes what Veil protects against, what it does not protect against, and the deployment choices that change those boundaries.
What Veil protects against
- Agent seeing real secrets in
.envfiles..envfiles contain format-valid placeholders; the agent's filesystem reads return those, never the real value. - Agent exfiltrating real secrets in outbound HTTP. The proxy intercepts request headers, URL query strings, and text-ish request bodies. If the agent tries to ship a real credential it never legitimately saw, it simply cannot — it has no handle on the real value.
- Same-host users reading the audit log. Audit DB files are chmod'd
to
0600and the parent directory to0700on everyveil run. Other users on the machine cannot read which credentials were injected, for which hosts, or when.
What Veil does NOT protect against
- Same-UID tampering of the audit log. The agent process runs as the same UID as Veil, so it has filesystem access to the audit DB. It can read, truncate, or forge rows. If your agent is compromised, its audit trail is untrustworthy.
- Long-running proxy holding credentials in memory. While
veil runis active, real secrets sit in the proxy's memory for routing. A memory read via/proc/<pid>/memor a debugger can extract them. We accept this by design — format-preserving injection requires the real value. - Non-HTTP exfiltration. Veil only mediates
HTTP_PROXY/HTTPS_PROXYtraffic. An agent that opens a raw TCP connection, sends DNS queries with data embedded in names, or uses any other channel is out of scope. - Secrets Veil does not manage. v1 covers
Authorization: Bearercredentials sourced from.envfiles. Secrets stored elsewhere (shell environment, MCP config files, application-managed credential stores) and credentials consumed by schemes Veil does not rewrite (HTTP Basic, AWS SigV4, GitHub App JWT, HMAC webhook signing, mTLS) remain in their original form. The agent reads and uses those real values unmediated. v1 is explicit about this — it is not silent failure but a documented exclusion (see MVP.md §5). - Agent direct vault reads. If the agent runs tools (shell, file
read) it may open
.veil/vault.bindirectly. The vault is encrypted, but the master key is obtainable via the OS keyring by any process running as the same user. - Placeholder fingerprinting via sentinel substring. Every
Veil-generated placeholder embeds a literal
VEILsubstring as a fail-closed leak sentinel; an agent that scans its inputs forVEILcan identify which.envvalues are placeholders. The agent learns nothing about the real secret. This is consistent with the cooperative-but-curious model — guaranteed detectability of a leaked placeholder is a stronger property than indistinguishability. - Same-session CA misuse. Veil's CA is not installed in any OS or
browser trust store. At
veil runtime, the CA is exposed to the child process only — viaSSL_CERT_FILE,NODE_EXTRA_CA_CERTS,CURL_CA_BUNDLE, andREQUESTS_CA_BUNDLE. Anything launched by that child (subprocesses, shell-outs) inherits those vars and therefore trusts the CA for the duration of the session. Veil does not protect against a compromised agent abusing its own session-scoped trust to intercept TLS within its own process tree. This is a deliberately narrower scope than a system-installed root would have.
What's not covered by the CA bundle injection
Some HTTPS clients ignore the standard SSL_CERT_FILE /
NODE_EXTRA_CA_CERTS / CURL_CA_BUNDLE / REQUESTS_CA_BUNDLE
environment variables and therefore will not trust Veil's CA when
launched under veil run. These include the JVM (which reads
$JAVA_HOME/lib/security/cacerts), Firefox (which uses its own NSS
store), native macOS apps that go through Apple's SecureTransport /
Network.framework APIs directly, and Go binaries that compile in their
own root pool via crypto/x509. Requests from these clients will fail
TLS verification at Veil's proxy. We accept this as an intentional limit
on blast radius: a CA that's only trusted by processes Veil itself
launched cannot be silently abused by anything else on the user's
machine.
Deployment notes for hardened setups
- Separate UID. Running Veil under a user different from the agent eliminates same-UID tampering and direct vault reads. This requires a setuid helper or systemd/launchd user service configuration; not supported out-of-the-box in v1.
- Short-lived sessions. Keep
veil runsessions as short as possible to minimize the in-memory credential window. - Network-level egress rules. Pair Veil with outbound firewall rules so the agent cannot reach hosts outside the expected provider set.
Known limitations called out in the code
- Compressed request bodies. Requests with a non-
identityContent-Encodingheader are rejected with HTTP 502 (fail-closed). Veil does not decompress→inject→recompress, and refuses to forward payloads it cannot scan. - Body injection allowlist. Only
application/json,application/x-www-form-urlencoded,application/xml,application/yaml,application/x-yaml,application/toml,application/x-ndjson,application/graphql,text/*, andapplication/*+json/*+xmlare scanned. Binary types and unknown Content-Types pass through. - Large bodies. Bodies larger than 10 MiB are not scanned.