Silent-on-Forbidden: Good for Security, Bad for Developer UX
There's a pattern in cybersecurity called silent-drop or silent-on-forbidden: when a request is unauthorized, return nothing, or return something indistinguishable from "not found", so an attacker gains no oracle to probe with. WireGuard does this at the network layer; firewalls have done it for decades; RFC 9110 §15.5.4 even sanctions returning 404 instead of 403 to hide a resource's existence. In its proper scope (anonymous, internet-facing channels where every bit of feedback measurably helps brute-force), this is sound. My objection isn't to the principle, it's to making it the default. Most applications aren't anonymous network protocols, they're authenticated systems where legitimate users and developers need to know why something failed. Applied universally, silent-on-forbidden trades a small security gain for a large debuggability cost.
PostgREST is the case that crystallized this for me. The promise is gorgeous: solve authorization once, at the database, with row-level security. The reality is that a forbidden access becomes a 200 OK with [], semantically identical to "you have no matching rows". The developer who expected a 403 is left chasing ghosts; the framework has collapsed two very different outcomes into one response. HTTP doesn't forbid this ([] is a valid representation of an existing collection), but it doesn't endorse it as an authorization signal either. What looks like elegant single-source-of-truth security turns into a debugging tax paid on every endpoint, every day.
This matters more now that agents write and operate code. Coding agents reason from feedback loops: a 401 means re-authenticate, 403 means change scope, 404 means wrong path. Give them clear status codes and they thrive. Give them 200 OK with an empty array when access is denied and they confidently move on, treating the silence as success; the bug stays, and the loop never closes. Security-by-default is good. Silence-by-default is a tax on every human and every agent who later has to figure out what your API actually meant.