Whetstone.
The Execution EnvironmentPermissions, and the fail-open trap
Module 2, Lesson 319 min

Permissions, and the fail-open trap

Three properties. The third one runs against everything your instincts have been trained on, and that is what makes it examinable.

How a permission list is evaluated

  1. In declaration order. The order you write the rules is the order they are considered.
  2. First match wins. Evaluation stops at the first rule whose pattern matches, and everything below it is never consulted.
  3. If nothing matches, the operation is allowed.

Order shadows

First-match-wins plus declaration order means a broad rule placed early shadows everything below it. Consider a list that looks entirely reasonable:

Looks safe. Is not.
1. allow  /workspace/**
2. deny   /workspace/secrets/**

A write to /workspace/secrets/key.pem matches rule 1, evaluation stops, and the write is allowed. Rule 2 was never reached. It is decoration in a security-critical file, which is the worst kind of decoration there is.

Flip it and add the piece almost everyone leaves off:

Correct: specific, then broad, then catch-all
1. deny   /workspace/secrets/**
2. allow  /workspace/**
3. deny   /**

Rule 3 is the fail-open fix in its natural habitat. Without it, anything outside /workspace matches nothing and is therefore permitted, including paths you never imagined the agent would reach.

Why competence is the failure mode

The wrong answer here is produced by experience, which is unusual and worth naming.

Someone who has never configured a policy engine has no strong intuition about evaluation semantics. Someone with a decade of security work has a very strong one, and it says: deny by default, specific beats general, deny overrides allow. Those are three sensible models. None of them is this model.

The more policy engines you have configured, the more confidently you will get this wrong, which is precisely the profile of the person sitting a certification exam. That is presumably why it is on it.

Where permissions stop

Permissions are static rules over paths. Two things they cannot do, both of which have their own lever elsewhere in this course.

They cannot express “it depends”. A decision that needs a human belongs in interrupt_on, from module 1, and the two compose: gate the irreversible operations, scope the rest with paths.

They cannot cover what you did not think of, and here the failure direction is the bad one. A gate you forgot to configure means a tool runs unsupervised. A permission you forgot to write means a path is open. Both fail toward capability.

And there is a third boundary that matters more in production than in the exam, because it decides what the list is actually protecting.

Read that alongside the module summary. A permission list scopes the file tools; it is not a filesystem boundary, and it is not a leash on the shell.

That is the module’s real summary. Deep Agents defaults toward capability at every layer: the shell policy runs on your host, the permission list allows what it does not mention, and execute ships registered. Each of those is defensible in isolation for a tool aimed at capable agents. Inheriting all three without reading them is how a demo becomes an incident.

Practice

Try it yourself

Quiz

When nothing matches

A filesystem operation is attempted and none of the declared permission rules matches its path. What happens?

  1. AThe agent pauses and asks a human to approve the operation
  2. BThe operation is denied, because nothing in the list granted it
  3. CThe agent raises a permission error and halts the run
  4. DThe operation is allowed, because filesystem permissions fail open
Show answer

Correct answer: D — The operation is allowed, because filesystem permissions fail open

Filesystem permissions fail open: no matching rule means allowed. Denial is what almost everyone picks, because every firewall, IAM policy and access control system they have ever configured denies by default, and that trained intuition is exactly backwards here. If you want deny-by-default you write the catch-all deny rule yourself, because nothing hands it to you.

Quiz

The rule that never runs

This list was written by someone being careful. A write to /workspace/secrets/key.pem is attempted.

Permission list as written
1. allow  /workspace/**
2. deny   /workspace/secrets/**
  1. ADenied, because a deny rule always overrides an allow rule
  2. BAllowed, because the broad allow matched first and evaluation stopped
  3. CDenied, because the more specific rule wins regardless of position
  4. DUndefined, because the two rules conflict with each other
Show answer

Correct answer: B — Allowed, because the broad allow matched first and evaluation stopped

First match wins on declaration order, so rule 1 matches and rule 2 is never reached. It is decoration. Options one and three both encode a specificity-beats-position model, which is how many real policy engines work and is exactly why this list looks safe to the person writing it. Here position is everything and the deny has to come first.

Recall

The three properties

Three facts that together fully determine behaviour. Get any one wrong and you get a different answer, which is what makes this a clean four-option question for an examiner.

State the three rules governing how filesystem permissions are evaluated in Deep Agents, and the practical consequence of all three together.

Reveal answer

One, rules evaluate in declaration order. Two, first match wins, so evaluation stops at the first matching rule and later rules are never consulted. Three, if nothing matches, the operation is allowed, so the system fails open. The consequence is that specific rules must be declared before general ones, and that an explicit catch-all deny at the end is the only way to get deny-by-default behaviour.

Quiz

Fix the list

Which rewrite gives you deny-by-default with a readable workspace and a protected secrets path?

Two candidate rewrites
Candidate A                     Candidate B
  allow /workspace/**             deny  /workspace/secrets/**
  deny  /workspace/secrets/**     allow /workspace/**
  deny  /**                       deny  /**
  1. ACandidate A, because the allow establishes the working area first
  2. BCandidate B, because the specific deny is declared before the broad allow
  3. CBoth work, since the catch-all deny is present in each candidate
  4. DNeither, because a catch-all deny blocks the agent's own scratch files
Show answer

Correct answer: B — Candidate B, because the specific deny is declared before the broad allow

Candidate B is correct: specific deny first, then the broad allow, then the catch-all. Candidate A repeats the shadowing bug, and its final catch-all is what makes it feel safe, which is the trap. A catch-all at the end cannot rescue a rule that was already shadowed higher up, because evaluation never reaches the bottom of the list for a path that matched at the top.

Quiz

Who gets this wrong

This question is unusual in that experience makes performance worse. Why?

  1. ABecause the documentation is ambiguous about the default outcome here
  2. BBecause deny-by-default is a newer convention that older engineers missed
  3. CBecause policy-engine experience trains a deny-by-default intuition that fails here
  4. DBecause the behaviour changed in v0.7 and older material is still circulating
Show answer

Correct answer: C — Because policy-engine experience trains a deny-by-default intuition that fails here

Someone who has never configured a policy engine has no strong intuition here. Someone with ten years of security work has a very strong one, and it says deny-by-default, specific-beats-general, deny-overrides-allow. Every one of those is a reasonable model and none of them is this model. The fourth option is worth ruling out explicitly: this is not a version change, so do not go looking for a release note to reconcile it against.

Do

Write a safe list

Ten minutes, scratch file, no runtime needed. Order is the entire exercise.

  • Write a list that allows reads across a project directory, forbids anything under a secrets path, and forbids everything else.
  • Read your list top to bottom and, for each rule, ask whether anything above it already matched the same path.
  • Delete the catch-all deny and write down in one sentence what becomes reachable.
Done whenMy deny rules for specific paths come before my broad allow, my list ends with an explicit catch-all deny, and I can name a concrete path that becomes reachable without it.
Sign in to track your progress →