2026-07-08
This authorization layer gates every action in the app. A user must possess every permission listed for the action they're attempting. Simple, defensive, and — as of the last deploy — catastrophically wrong.
REQUIRED_PERMISSIONS = {
"read_docs": ["docs.read"],
"edit_docs": ["docs.read", "docs.write"],
"admin_panel": ["admin"],
}
def user_can_perform(user, action):
required = REQUIRED_PERMISSIONS.get(action, [])
return all(user.has(perm) for perm in required)
def handle_request(user, action):
if not user_can_perform(user, action):
return "403 Forbidden"
return execute(action)
# A new endpoint ships:
# handle_request(guest_user, "delete_all_users")
# Nobody remembered to add "delete_all_users" to REQUIRED_PERMISSIONS.
# The guest gets a 200.
Look at what happens when action isn't in the dict:
REQUIRED_PERMISSIONS.get("delete_all_users", []) returns [].all(user.has(p) for p in []) returns True.This is vacuous truth. Mathematically, "every element of the empty set satisfies P" is true, because there's no counterexample. Python faithfully implements this: all([]) is True, and dually, any([]) is False. The generator yields nothing, so all never sees a falsy value, so it returns its identity element for AND — which is True.
The bug lives at the intersection of two innocuous choices: dict.get(..., []) to avoid KeyError, and all() to express "must have every permission." Individually, both are idiomatic. Composed, they turn "unknown action" into "no restrictions."
The same shape appears everywhere:
if all(check(x) for x in items): ship() — ships on empty input.if not any(is_bad(x) for x in errors): commit() — commits when the error list is empty and when it forgot to load.WHERE id IN () is a syntax error, but frameworks that build the list dynamically sometimes emit WHERE TRUE as a fallback. Same trap.Treat "no rule registered" as a distinct state — not as "no rule needed." Fail closed:
def user_can_perform(user, action):
if action not in REQUIRED_PERMISSIONS:
raise UnknownAction(action) # or: return False
required = REQUIRED_PERMISSIONS[action]
if not required:
return False # explicit: empty = deny
return all(user.has(perm) for perm in required)
If you genuinely want "empty means allowed" (say, for public endpoints), spell it out with a sentinel — PUBLIC = None and an is None check — so the intent lives in the code, not in a coincidence of set theory.
The deeper lesson: all()/any() on a possibly-empty iterable is a decision, not a default. Any predicate over "all X" implicitly answers "and what if there are no X?" — and Python answers "yes" whether you meant it or not. Every authorization check, every "all validations passed," every "no errors present" gate should think about the empty case explicitly, because your test suite almost certainly won't. The lookup that returns [] is the one that ships to production.
all([]) is True and any([]) is False — so any predicate you evaluate over a "missing" collection silently answers the vacuous case, and in security-adjacent code that answer is almost always the wrong one.
