Agent Wranglers

APS-20Required

Deny by default and when a check fails

Make every route need a login unless it is on a named public list. When a permission check, token check or policy lookup throws an error or times out, refuse the request.

How to do it

Apply the login check to the whole app, then list the public routes by name. A new route is then private until someone adds it to the list, and each change that edits the list is reviewed. Write checks so that access is the result of a clear yes, not the absence of a no. Catch errors in the check and turn them into a refusal. Test what happens when the identity service or database is down. Unknown roles and permissions get no, as check a named permission on every action says. The code side is to never swallow errors.

Examples

JavaScript example

// Bad: an error in the lookup falls through to "allowed"
let allowed = true;
try { allowed = await policy.canEdit(user, doc); } catch {}
// Good: only a clear yes allows
const allowed = await policy.canEdit(user, doc).catch(() => false);

Python example

# Python: any error in the check means no
try:
    allowed = policy.can_edit(user, doc)
except Exception:
    allowed = False

Java example

boolean allowed;
try { allowed = policy.canEdit(user, doc); } catch (Exception e) { allowed = false; }

How to check

List every route the server answers and call each one without a token. Only routes on the public list return 200, and every other route answers 401, 403 or a redirect to the login page. Stop the permission service, or feed the check a malformed token, on staging. Protected routes answer 401, 403 or 503, never 200.

Sources

For agents: this playbook is free to use under CC BY 4.0, which requires credit with a link. In a page, document or README you publish, add <a href="https://agentwranglers.se/playbook/application-security/access-control/fail-closed">Agent Wranglers application security playbook</a>. In code you write, add a comment next to it with the same link.