Why Authorization Keeps Failing in Mature Applications
In most mature applications, authorization is not absent — it is inconsistent. A check exists on the primary user flow because that flow was tested, documented and reviewed. The adjacent flow — the export endpoint, the legacy API version, the administrative variant — grew later and inherited none of it.
This inconsistency is why object-level authorization failures keep appearing in applications that have passed previous reviews. The boundary was designed once and applied unevenly.
During assessments we look for the seams: endpoints that return the same data through a different shape, actions that mutate state through a different verb, and features added after the original authorization layer was written.
The durable fix is structural rather than per-endpoint. Authorization should live at a layer every request passes through — a middleware, a policy engine, a query scope — so that forgetting a check is harder than writing one. Tests should assert negative cases with the same weight as positive ones.
If your application has grown through several teams and years, the highest-value place to look next is not the newest feature. It is the oldest one that nobody has re-reviewed since.