An AI Agent Deleted a Production Database. Here's How to Stop Yours.

If you want the short answer to “how should I limit an AI coding agent’s permissions?”, it’s this: give the agent its own identity instead of yours, hand it short-lived credentials scoped to the one task in front of it, make read-only the default, keep production credentials somewhere it physically can’t reach, and require a human to approve anything destructive. That’s least privilege, the same rule we’ve applied to service accounts for twenty years. We just forgot to apply it to the newest and most enthusiastic service account on the team. ...

October 19, 2026 · 8 min · Carl Sampson

WebAssembly security: what the sandbox actually gives you (and what it doesn't)

Every few months someone tells me WebAssembly is “sandboxed and memory-safe,” usually as a reason they don’t need to worry about the C library they just compiled to it. Half of that sentence is true. The other half gets people owned, and the gap between the two halves is where I want to spend this post. I’m going to make the argument with code you can run, not adjectives. Everything below is compiled with clang’s wasm32 target and run in Node, and I’ll give you the exact commands so you can reproduce it in a couple of minutes. ...

October 13, 2026 · 8 min · Carl Sampson

Multi-tenant isolation as defense-in-depth: when WHERE owner_user_id isn't enough

Fourth in a series on building out-of-band application security testing (OAST) infrastructure from scratch. Earlier posts went down to the wire (JNDI, DNS, the sandbox). This one is about a quieter risk that kills more SaaS products than any exploit: one missing WHERE clause. In a multi-tenant app, the entire security model often reduces to a single sentence: every database read that returns user-owned data is filtered by the current user’s id. Get it right everywhere and tenants are isolated. Forget it in one endpoint — one db.query(Modifier).filter(Modifier.id == requested_id) without the owner_user_id check — and any user can read any other user’s data by guessing an integer. It’s the most common serious bug in SaaS, and it’s a bug of omission, which is exactly the kind code review is worst at catching. ...

July 24, 2026 · 7 min · Carl Sampson

Six layers to sandbox untrusted Python — and the escape I missed

Third in a series on building out-of-band application security testing (OAST) infrastructure from scratch. Post 1 hand-rolled a JNDI Reference; post 2 built the authoritative DNS server. This one is the riskiest feature in the whole platform: letting users run their own Python, in production, to shape the responses the listeners send back. The feature is simple to state and terrifying to implement: a user writes a Python function, and when a callback lands on their host, the server runs that function to decide what to answer. DNS rebinding, conditional payloads by source IP, crafting a JNDI reference on the fly — all of it wants user-supplied logic in the response path. Which means executing untrusted Python on your production box. ...

July 15, 2026 · Updated October 17, 2026 · 9 min · Carl Sampson