Fix BOLA (Broken Object Level Authorization) in Rails
Generated remediation sketch. GuardAPI the product only gates GET BOLA in CI.
BOLA (OWASP API1) is the ultimate low-hanging fruit for attackers. It occurs when your API trusts the ID provided in the request without verifying the requester's ownership. In Rails, this is usually caused by lazy controller lookups that ignore the current user's session context, allowing anyone to enumerate and exfiltrate records by simply incrementing an integer or guessing a UUID.
The Vulnerable Pattern
class InvoicesController < ApplicationController
# GET /invoices/:id
def show
# VULNERABLE: Direct lookup from the global model scope.
# An attacker can change the ID in the URL to view any user's invoice.
@invoice = Invoice.find(params[:id])
render json: @invoice
end
end
The Secure Implementation
The fix relies on 'Relationship-Based Access Control'. Instead of querying the top-level 'Invoice' class, we chain the query through the 'current_user' association. This ensures that the database-level query is constrained to records owned by the requester. If the ID exists but belongs to another user, ActiveRecord will return a 404 (RecordNotFound) instead of leaking data. For complex apps, use a gem like Pundit to enforce 'authorize @record' patterns, which centralizes this logic into Policy objects.
class InvoicesController < ApplicationController
# GET /invoices/:id
def show
# SECURE: Scope the lookup to the authenticated user's own records.
# This automatically appends 'WHERE user_id = ?' to the SQL query.
@invoice = current_user.invoices.find_by!(id: params[:id])
render json: @invoice
rescue ActiveRecord::RecordNotFound
render json: { error: 'Resource not found or unauthorized' }, status: :not_found
end
end
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