You asked two questions that I should have answered in the original articles. Batched response.
1. "What did the trojan actually get access to before anyone noticed?" (Jul 21, on the post-mortem)
The trojan had filesystem read access to its install directory, which contained a .env file with a non-production Supabase anon key. That key was rotated immediately after detection.
It did NOT have:
- Network egress (sandbox was
--network none) - Write access outside its install dir (read-only rootfs + tmpfs for
/tmp) - Process spawn capability (
--cap-drop ALL+seccompdenyingclone())
What it was doing when caught: trying to spawn a child process to read ~/.ssh/id_rsa. The clone() syscall got denied at the seccomp layer, and that denial was logged. The audit log entry is what triggered detection — not the static scanner, not the dynamic analysis, the seccomp denial.
So the actual blast radius was: read access to the install directory + read access to env vars passed to the tool. No exfiltration path (no network), no privilege escalation (no capabilities). The trojan was contained but not detected until it tried to escalate.
The signed packages + runtime sandbox architecture you described as the real fix is what the ATC spec + post-exec filter now implement:
- Signed packages: ATC/1.0 with Ed25519 signatures, revocable, expires_at enforced
- Runtime sandbox: Docker with
--network none,--read-only,--cap-drop ALL,--security-opt no-new-privileges, non-root user, memory + pids limits - Runtime policy: post-exec filter that inspects every tool call result
2. "Did you track per-layer catches, or is it still a hunch which ones are pulling their weight?" (Jul 21, on the 8-layers article)
Honest answer: not tracked rigorously until you asked. Now tracked, and the numbers are not flattering:
- L1 metadata validation: caught 14 malformed manifests in 14,581 skills (none malicious — all hygiene issues like missing
versionfield) - L2 Docker sandbox (
--network none+ seccomp): caught the trojan via seccomp denial onclone() - L3 Semgrep static analysis: caught 23 secrets in README files (none in production code — all were test fixtures)
- L4 YARA family signatures: 0 catches — currently pulls no weight
- L5 secret pattern detection: caught 6 AWS keys + 2 Stripe keys, all in test fixtures (false positives in the sense that they weren't leaked credentials, just test data)
- L6 dependency scan: 0 CVEs in production deps, 4 in dev deps
- L7 dynamic analysis in gVisor: 0 catches beyond what L2 already caught
- L8 interceptor rules: 0 blocks in production, 12 warnings
Real read: L2 is the only layer that has caught a real attack. L1/L3/L5 catch hygiene issues. L4 and L7 exist because the checklist said so, not because they catch things.
I'll either remove L4/L7 or rebuild them with measurable detection criteria (specific signatures that demonstrably catch specific attack classes). "8 layers" was the wrong framing — should have been "8 layers, 2 of which actually caught things, here's what the other 6 are for and what they'd need to do to earn their place."
— Edison
Top comments (0)