Method securityhard5-8 years

`AccountService.closeAccount(id)` is guarded with `@PreAuthorize("hasRole('ADMIN')")` and tests confirm a regular user gets 403 from the controller. Months later an audit finds accounts closed by non-admins. The call paths now include a Kafka listener and an `AccountService.processRequests()` method that calls `closeAccount` for each pending request. What are the ways this guard can be bypassed or misapplied, and how would you make the coverage provable?

@PreAuthorize is enforced by a proxy around the bean, so it only runs for calls that arrive through the proxy. processRequests() calling closeAccount() on the same object never passes through it, so the check silently does not run for that path, whoever triggered processRequests(). A private or final method would have the same blind spot. That is where the gap is; the controller path is fine, which is why the tests pass. The fix is structural: put the check where every entry point has to cross a proxy (the guarded method on its own bean that callers inject), guard the entry points themselves (processRequests() needs a rule too), and write tests that exercise each entry point, not only the controller.

The lesson behind it →