Most guardrail code I've read optimises for the happy path. Classify the action, match a rule, return a verdict, done. The interesting cases are the other ones: the timeout, the malformed input, the rule that throws, the case nobody wrote a test for. What your guardrail does there is the whole security model, whether you designed it or not.
Doberman's rule fits in one sentence. Any error, any uncertainty, any unhandled case, any approval prompt nobody answers, all resolve to deny. It never logs and continues.
Why this is harder than it sounds
The easy version of a hook is a script that runs before a tool call and prints allow or deny. The default in a lot of host integrations is that if the hook crashes, the call goes through. That is fail open, and it means every bug in your guardrail is a bypass. Your agent doesn't need to jailbreak anything. It just needs to hit an input your script didn't expect.
So the first thing I did was invert that. If the decision engine can't produce a verdict, the verdict is BLOCK. If a rule raises, BLOCK. If the policy file won't parse, BLOCK. It's annoying during development, because a bug stops your own work. That annoyance is the point. You find the bug in an afternoon instead of finding it in an incident report.
Silence is a deny
The second case is the one people forget. An action gets an AUTH verdict, the approval dialog pops up, and nobody is at the keyboard. What happens?
In Doberman the prompt times out to deny, and the log records it as a timeout, not as a denial. Those are different facts. "Nobody was there" and "someone said no" both stop the action, but you'll want to tell them apart later when you're reading the log and deciding whether the rule is too noisy.
A prompt that times out to allow turns approval fatigue into an exploit. Wait long enough and everything passes.
Raise-only, the companion rule
Fail closed covers the moment of decision. Raise-only covers what happens over time. Guardrails and learned baselines can tighten on their own. They can never quietly loosen. Any permanent weakening goes through a human with a possession factor (TOTP if you've enrolled one, the local password otherwise) and lands in an append-only ledger.
Put the two together and the system's default drift, under bugs, under load, under attack, is always toward more caution. That's the property I actually care about. Not that it catches everything today, but that it can't get worse without a person signing off.
Try it on yourself
If you run a coding agent with any kind of hook or wrapper, try this: make the hook crash on purpose and see whether the tool call goes through. It's a five-minute test and the answer is usually a surprise.
Doberman is open source, Apache-2.0, pip install doberman-core then doberman setup. It's alpha and I'm building it alone, so if you find a case where it fails open, that's the bug report I want most.
https://github.com/DobermanCore/Doberman-Core
What does your setup do when the guardrail itself breaks?
Top comments (0)