Fix BOLA (Broken Object Level Authorization) in Spring Boot
Generated remediation sketch. GuardAPI the product only gates GET BOLA in CI.
BOLA (Broken Object Level Authorization), formerly known as IDOR, is the most critical vulnerability in modern API security. In Spring Boot, it manifests when a controller blindly trusts a client-provided ID to fetch a resource without verifying if the authenticated principal owns that specific object. If you're just calling repository.findById(id) without checking the owner, you're leaking data. Period.
The Vulnerable Pattern
@GetMapping("/api/v1/invoices/{id}")
public Invoice getInvoice(@PathVariable Long id) {
// VULNERABILITY: Any authenticated user can access any invoice ID
return invoiceRepository.findById(id)
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND));
}
The Secure Implementation
To kill BOLA, you must enforce ownership at the logic or data layer. The secure example uses two patterns: 1. A custom SecurityService with @PreAuthorize to check resource ownership before the method executes. 2. Scoped Queries, which is the gold standard. Instead of fetching by ID alone, your JPA repository should fetch by ID AND the User ID extracted from the SecurityContext. If a user tries to access an ID they don't own, the query returns null, effectively treating unauthorized access as a '404 Not Found', which prevents resource enumeration.
@GetMapping("/api/v1/invoices/{id}") @PreAuthorize("@securityService.isInvoiceOwner(authentication, #id)") public Invoice getInvoice(@PathVariable Long id) { return invoiceRepository.findById(id) .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND)); }
// Alternative: Scoped Query (Defense in Depth) @Query(“SELECT i FROM Invoice i WHERE i.id = :id AND i.user.username = :username”) OptionalfindByIdAndOwner(Long id, String username);
Prove it on the next pull request
This page is a generated code sketch, not a GuardAPI scan. After you scope the query by tenant, fail the GitHub job when tenant B can still GET tenant A's object. GET-only. Tokens stay in GitHub Secrets.
- uses: GuardAPI/ghost-api@v6
with:
api-key: ${{ secrets.GUARD_API_KEY }}
openapi-path: ./openapi.json
base-url: ${{ secrets.STAGING_API_URL }}
token-a: ${{ secrets.TOKEN_USER_A }}
token-b: ${{ secrets.TOKEN_USER_B }}
About this page
Framework notes in /guides are generated sketches kept for URL stability. They are not human pentest reports and they are not GuardAPI scan output. The product is a GET-only BOLA merge gate. Maintained by GuardAPI. Questions: support@guard-api.com