2026-10-03 · web
A matcher is not a security boundary
A proxy or middleware matcher decides which requests run a piece of code. It does not decide who is allowed to use what sits behind it. When authorisation exists only as a path pattern in front of the handlers, every gap between what the pattern matches and what the router eventually resolves becomes a way around it: encoded characters, trailing slashes, alternate prefixes, internal headers.
Next.js showed this in 2025 with CVE-2025-29927, where a crafted header let requests skip middleware entirely. That specific bug is fixed; the structural lesson is not. Check authorisation inside every Route Handler, Server Action and data-access function, as close to the data as possible, and deny by default. Keep the edge layer for what it is good at: cheap early rejection and redirects.
A quick test: switch the proxy off in a staging environment and see what is still reachable. If anything sensitive is, the proxy was carrying weight it was never designed to carry.
2026-10-03 · ai
Tool output is untrusted input
In an LLM agent, instructions and data arrive through the same channel: text. A web page the agent fetches, a file it opens or an issue comment it reads all land in the same context as the system prompt, and the model has no reliable way to tell which parts are meant to be obeyed. That is the core of prompt injection (LLM01 in the OWASP Top 10 for LLM Applications), and it is closer to a confused-deputy problem than a prompting problem.
Filtering for suspicious phrases helps at the margins. The more durable controls are architectural: give each tool the least privilege it needs, avoid ambient authority, require human confirmation for irreversible or externally visible actions, and keep untrusted content away from tools that can exfiltrate or modify things.
Multi-agent systems add a further wrinkle. When one agent passes its output to another, injected text can ride along and gain authority at each hop. Treat every hop as a trust boundary, and log what crossed it.
2026-10-03 · builds
If you cannot rebuild it, you cannot trust it
Source review answers one question: is this code safe? It says nothing about whether the binary you run was built from that code. Between the two sit a compiler, a build server, a dependency graph and the people who operate them, and any of them can change the result.
A reproducible build closes that gap. Given the same source and the same toolchain, anyone can rebuild the artifact and get the same bytes. That takes pinned toolchains and dependencies, no embedded timestamps or build paths, and deterministic ordering of files and archives. In return, the claim “this is what was reviewed” becomes something a third party can check instead of something a maintainer asserts.
Reproducibility does not make code safe; a faithfully reproduced backdoor is still a backdoor. What it does is shrink the set of things you have to trust down to the source itself, which is where review effort belongs.
2026-10-03 · isolation
An air gap is a process, not a product
An air gap removes the network path. It does not remove data movement. Every USB drive, software update, file transfer and maintenance laptop is a channel into and out of the isolated side, and those channels are where air-gapped designs tend to fail.
So model the transfers, not just the gap: which direction data may flow, what is checked on the way in, which media is dedicated to the purpose, who is accountable and what is logged. One-way flows and dedicated, labelled media are boring controls that do most of the work.
Then be honest about what remains. Academic work has shown covert channels out of air-gapped machines using sound, light, heat and electromagnetic emissions. These raise the cost of an attack rather than removing it, which is the right way to think about the gap in general: a strong control whose value depends on the discipline around it.
2026-10-03 · writing
Document the threat model, not just the bug
A vulnerability report that only says “this is broken” is a trick: impressive once, hard to reuse. What makes research useful is the context around the break: what the system assumed, who the attacker was allowed to be, which boundary failed and why.
Every report on this site follows the same shape: summary, impact, a minimal reproduction, root cause, mitigation and a disclosure timeline, published under a stated threat model. Writing the assumptions down first also makes the work harder to fool myself with, because a finding that only works under an unrealistic attacker model shows itself quickly.
The goal is for another engineer to read the write-up, understand the class of problem and find it in their own systems, without ever needing to see an exploit.