---
title: "Glossary: Deny by default"
canonical_url: "https://tokenobserve.com/glossary/deny-by-default"
published: 2026-09-02
last_updated: 2026-10-21
---

# Glossary: Deny by default

Deny by default is an authorisation model in which an action is refused unless some permission explicitly allows it, and in which an explicit deny overrides every allow. An agent holding no roles, a role with an empty permission list, and a resource no permission names all produce the same answer, a refusal, so the failure mode of a misconfiguration is a blocked request somebody notices rather than a standing grant nobody does.

## Also called

- default deny
- deny-by-default
- implicit deny

## In practice

The mechanism is short enough to state completely. Collect every permission on every role the caller holds. If any of them matches the resource and the action and its effect is deny, refuse immediately and record which role and which pattern decided it. Otherwise, if any matching permission allows, permit and record that one. Otherwise refuse, with a reason that says so in those words. Three properties fall out of that ordering.

The first is that precedence does not depend on ordering. Because the deny path returns before any allow is settled on, a narrow guardrail wins whether it is written above the broad grant, below it, or inside the same role. That is what makes a subtractive guardrail a pattern an operator can rely on rather than a race: you can grant a whole tool namespace to a team and remove one action from one agent, without rewriting the broad grant or duplicating it into a narrower one. Under allow-wins semantics the same configuration is a coin toss decided by role iteration order, the kind of thing that changes silently in a refactor.

The second is that absence is an answer. There is no implicit grant anywhere, so the empty cases are all safe: an agent with no roles can do nothing, a role someone created and never populated grants nothing, and a resource nobody thought about is refused. This is the property that keeps working when everything cleverer has failed, which is why deny by default is worth having before any policy engine, any anomaly detection and any classifier.

The third is that the failure mode is inverted deliberately, and that has a cost somebody has to pay. Deny by default produces breakage, and the breakage lands on whoever shipped the agent. That is deliberate: under-privilege arrives as a ticket an engineer raises, while over-privilege arrives as an incident eighteen months later that nobody files at all. It only holds if refusals are legible. A refusal has to name the role and the pattern that produced it. When it does not, the engineer debugging a failing agent widens the broadest grant they can find until the error stops, and the model has been defeated by its own error messages.

Deny by default is often mistaken for other things. It is not least privilege: a system can deny by default and still hand out a wildcard permission that allows everything, and in most estates that grant exists somewhere. It is not zero trust, which is a network and authentication posture rather than an authorisation default. It is not argument-aware: a rule such as refunds above a threshold need a human is a policy, because a permission model knows the tool and not the amount. And it says nothing about time: a grant stands until someone edits the role, so deny by default without periodic review is a snapshot of intentions from whenever the roles were last written.

It is defeated in recurring ways, all of them local decisions that look reasonable. A wildcard grant issued to unblock a launch and never narrowed. Roles scoped to a team rather than to an agent, so every agent on the team holds the union of what the team needs. A deny list used as though it were an allowlist, which only covers the resources someone had already thought of. And a filtered catalogue mistaken for enforcement: hiding a tool from the list an agent is shown is a usability feature, and the authorisation decision still has to be taken when the call arrives.

## Example: One role, two answers

A role called finance-support carries two permissions: allow invoke on every tool on the payments server, and deny invoke on the refund tool specifically. A call to the payment status tool is allowed, and the record names the role and the wildcard pattern that permitted it. A call to the refund tool is refused, and the record names the role and the exact pattern that denied it. It is refused whichever order the two permissions happen to be listed in, and whether they sit in one role or two. A third call, to a tool on a server nobody has granted at all, is refused with a reason ending in “deny by default”: no permission mentions it, and no permission mentioning it is the answer.

## Routinely confused with

Least privilege: Least privilege is a goal about how much authority a principal ends up with. Deny by default is a mechanism about what happens when nobody has said anything. You can satisfy the mechanism and miss the goal by granting a wildcard, which is why the two claims should never be made as one.

Allowlist and blocklist: Deny by default is the allowlist stance made structural: everything absent is refused. A blocklist refuses only what somebody has already named, so its coverage is bounded by imagination. A system with both — an allowlist plus explicit denies that override it — uses the deny list for subtraction inside a grant, not as the primary control.

Zero trust: Zero trust is about not granting authority on the basis of network position, and it is satisfied by authenticating and authorising every request. It is silent on what the authorisation decision should be when no rule matches. Deny by default answers that question, and a system can be one without the other.
