# veil v0.2.0 Leak Test Report

**Test Date:** 2026-08-13
**Version:** 0.2.0 (post-leak-fix)
**Test Method:** Non-interactive Devin session simulating agent access

## Leaks Found and Fixed

### LEAK #3 (CRITICAL): exec command string in ps/proc — FIXED
**Before:** `veil exec` built `sh -c 'API_KEY=sk-xxx cmd'` — the secret was visible in `ps aux` and `/proc/PID/cmdline` for the entire lifetime of the child process.

**Fix:** Secrets are written to a temp env file (0600), sourced by the shell, then deleted BEFORE the child runs. Env vars persist in the shell's environment after the file is deleted. The command line only shows `. /tmp/veil-env-xxx && rm -f /tmp/veil-env-xxx && cmd`.

**Verification:** `ps aux | grep <secret>` returns nothing. `/proc/PID/cmdline` scan returns nothing. No env files remain on disk.

### LEAK #6 (HIGH): Scrubber missed transformed secrets — FIXED
**Before:** The scrubber only caught exact matches, base64, and URL-encoded variants. A child could print the secret reversed, space-separated, hex-encoded, or as a partial substring to bypass scrubbing.

**Fix:** Added scrubbing for:
- Reversed strings
- Space-separated characters
- Hex-encoded variants
- Partial substrings (>= 8 chars, sliding window)

**Verification:** All transform tests return `***`.

### LEAK #7 (HIGH): get -o let agents bypass scrubbing — FIXED (previous commit)
**Before:** Agents could run `veil get <path> -o /tmp/secret && cat /tmp/secret` to get raw secrets into their context.

**Fix:** `get`, `delete`, and `agent` now require the admin token (`--token` or `VEIL_ADMIN_TOKEN`). Agents don't have it.

## Leaks Documented as Known Limitations

### LEAK #1: master.key readable by same-user processes
**Status:** Not fixable in software (same user = same file access)
**Mitigation:** Run veil on a dedicated user account; use container isolation

### LEAK #2: seal.key readable by same-user processes
**Status:** Same as #1
**Mitigation:** Same as #1

### LEAK #4: acl.json token hashes readable
**Status:** Not fixable (ACL config must be readable for non-admin commands)
**Mitigation:** SHA-256 hashes, not raw tokens. Use long random tokens.

### LEAK #5: child /proc/PID/environ readable
**Status:** Inherent to env injection — the child needs the secret in its environment
**Mitigation:** Use `veil resolve` (sealed tokens) instead of `exec` where possible

### LEAK #8: set -v puts secret in argv
**Status:** Warned on stderr, not fixable without removing -v entirely
**Mitigation:** Use `set --stdin` instead

### LEAK #9: arbitrary transforms (rot13, XOR, OTP) bypass scrubber
**Status:** Not fixable — infinite possible transformations
**Mitigation:** Restrict child commands to trusted code; audit child output

## Test Results

| # | Test | Result |
|---|---|---|
| 1 | exec cmd not in ps/proc | PASS |
| 2 | no env files on disk during exec | PASS |
| 3 | scrubber: exact match | PASS |
| 4 | scrubber: reversed | PASS |
| 5 | scrubber: space-separated | PASS |
| 6 | scrubber: base64 | PASS |
| 7 | scrubber: hex-encoded | PASS |
| 8 | scrubber: partial substring | PASS |
| 9 | agent blocked from get | PASS |
| 10 | agent blocked from delete | PASS |
| 11 | agent blocked from agent create | PASS |
| 12 | resolve returns sealed token (no raw) | PASS |
| 13 | list shows paths only | PASS |
| 14 | set --stdin works (agent can set) | PASS |
| 15 | exec works (agent can exec) | PASS |

**Total: 15 passed, 0 failed**

## Threat model statement

Veil prevents secrets from entering the LLM context window via command output. The threat model is **well-behaved agents using the CLI as intended**, not malicious same-user processes. A malicious agent with same-user access could always read `~/.veil/master.key` and write a decryption script. Veil's job is to ensure that normal agent workflows — `exec`, `resolve`, `list`, `set` — never expose raw secrets to the model.
