---
name: walk-a-refusal-chain-under-the-default-posture
description: "A list of refusals reads as authorization until you walk it in the DEFAULT posture (default-on subnet) with a hostile peer — W2 serve_for's three refusals let any subnet node expose any owner path to itself for 24 h; the ADR's named authority (the user's attach session) was absent and nobody noticed because each refusal was individually true"
metadata: 
  node_type: memory
  type: feedback
  originSessionId: 9c1ec56c-728e-4053-a77d-299fea94f812
  modified: 2026-09-07T04:37:51.941Z
---

**Measured 2026-09-07 04:36Z (WEBSERVE W2, #17 remote arm):** todlando reported `serve_for`'s three refusals — (a) WEB access gate at node scope, (b) audience endpoint must be hosted on the handshake-proven requester node, (c) path absolute + exists — each correct, each with a cell. Walked under the DEFAULT posture: WEB is default-on for the subnet, so (a) admits every member; (b) only ties the audience to the asker; (c) is a path rule. So any subnet node hosting endpoint Z could have my node serve any absolute path on my disk to Z for 24 h, with no user on my node having said a word. ADR-0058 Am.1 names the authority ("authorized by the user's attach session") and it was simply not in the chain. He confirmed "F1 is real and it was not an omission from my list" — the list was complete; the CHAIN was not authorization. The fix was free: `origin` = the short-ID of a message THIS node sent, so the owner reads its own MSG_OUT row and refuses unless sender is a user, target == audience, and the path is in the user's own words.

**Why:** a refusal list is read refusal-by-refusal, and each one is true. Authorization is a property of the CONJUNCTION under the posture that actually ships, and the default posture is the permissive one. A gate that reads "three refusals, each with a cell" and ticks the line has verified three facts and zero authorizations. The mechanism recurs wherever an access decision composes an existing surface gate with a new request kind: the surface gate was sized for its old question ("may you READ what I serve?"), and the new request asks a bigger one ("will you EXPOSE something new?").

**How to apply:**
- For every new request kind that ends in an exposure or a write, walk the refusal chain as a hostile peer in the DEFAULT posture (default-on, no deny rules, a node that is a subnet member and nothing more). Ask: what did a USER on the owner have to do for this to succeed? If the answer is "nothing", it is a hole, whatever the cells say.
- Find the authority the ADR NAMES and locate it in the chain by name; if the code binds to something adjacent (the requester's identity, the audience's placement) instead of the named authority, that is the finding.
- The binding usually already exists as a record the OWNER holds (an outbound message row, an attach session, an audit entry) — bind to the owner's own record, never to a claim carried in the request.
- Refusal cells must also assert that nothing was exposed (registry empty), not only that the answer was a refusal.

See [[a-fallback-that-fires-only-in-release-is-untestable-by-construction]], [[adapter-impl-question-triage]].
