API Security in 2026: BOLA, Mass Assignment, and Authorization Patterns

Manish Garg
Manish Garg Associate of (ISC)² · RingSafe
May 22, 2026
9 min read

Introduction

APIs are the connective tissue of modern enterprise software and the predominant attack surface of 2026. The OWASP API Top 10 (2023 edition, with a 2026 update in draft) catalogues the recurring failure modes; the recent breaches at Indian fintechs and at global tech companies confirm that the same patterns repeat. Authorisation flaws — specifically Broken Object Level Authorization, Broken Object Property Level Authorization, and Broken Function Level Authorization — account for the majority of high-impact API breaches.

This guide is for backend engineers, AppSec architects, and security testers building defensible API authorisation. We cover the OWASP API Top 10 in operational terms, the canonical authorisation patterns (RBAC, ABAC, ReBAC), the testing methodologies, and the secure-by-default scaffolding that prevents the most common bugs from being written in the first place.

Background: Why API Authorisation Keeps Failing

Three structural factors:

Authorisation is per-request, per-resource. Authentication says “this is user X.” Authorisation must answer “is user X allowed to perform action Y on resource Z?” for every single request. Forgetting the check for one endpoint, on one method, in one branch, is a vulnerability. There is no compiler that catches missed authorisation.

APIs externalise data model decisions. A “user can edit their own profile” check is straightforward in a server-rendered application where the data model is hidden. In an API, the client passes the resource ID, and the server must verify that the ID belongs to the authenticated user — on every endpoint that takes a resource ID.

Microservices multiply enforcement surfaces. A request flows through API gateway, BFF, microservice A, microservice B, database. Each can do its own authorisation check, or rely on a peer. The “checked upstream” pattern fails when an attacker bypasses the upstream.

Theory: The OWASP API Top 10 in Operational Terms

API1 BOLA — Broken Object Level Authorization. The endpoint accepts a resource ID and serves the resource without verifying the caller has access. GET /api/invoices/{id} returning any invoice when authenticated. Most prevalent and highest-impact API vulnerability.

API2 Broken Authentication. JWT signature not validated; weak secrets; session tokens that do not expire; failure to invalidate on logout.

API3 BOPLA — Broken Object Property Level Authorization. The user is authorised to modify the object but allowed to modify properties they should not (e.g., PATCH /users/me {"role": "admin"}).

API4 Unrestricted Resource Consumption. No rate limits, no pagination caps, no payload size limits. Cost-amplification attacks: a single API call triggers expensive downstream work.

API5 Broken Function Level Authorization. Admin endpoints reachable by non-admin tokens; UI hides the button, but the API does not enforce the role.

API6 Unrestricted Access to Sensitive Business Flows. Automation-friendly endpoints (account creation, purchase) without anti-automation defences enable abuse beyond traditional confidentiality/integrity/availability.

API7 Server Side Request Forgery. An API takes a URL parameter and fetches it server-side, exposing internal services.

API8 Security Misconfiguration. Verbose error messages, missing security headers, default credentials.

API9 Improper Inventory Management. Old API versions still reachable; staging endpoints in production; undocumented internal endpoints.

API10 Unsafe Consumption of APIs. The API itself consumes third-party APIs unsafely — trusting responses, blindly proxying, exposing third-party errors.

Theory: Three Authorisation Models

RBAC (Role-Based Access Control). Users have roles; roles have permissions; permissions gate actions. Simple, well-understood, struggles with resource-level authorisation. A user has the “viewer” role — viewer of what?

ABAC (Attribute-Based Access Control). Decisions are made by policy that evaluates attributes of the subject, the resource, the action, and the environment. Express “tellers may view accounts in their own branch during business hours.” Powerful, harder to reason about, harder to test exhaustively. Implementations: OPA (Open Policy Agent), AWS IAM at scale, Cedar (AWS’s open-source policy language).

ReBAC (Relationship-Based Access Control). Decisions made by traversing a graph of relationships between principals and resources. “Alice can read this document because she is a member of a group that is a member of the workspace that owns the document.” Implementations: Google Zanzibar, OpenFGA, SpiceDB.

Most modern APIs combine: RBAC for coarse role gating + ABAC or ReBAC for resource-level checks. The choice depends on the data model. Collaborative tools (Notion, Figma, Slack) lean ReBAC. Financial systems lean ABAC. Simple admin tools live happily in RBAC.

Technical Deep Dive: BOLA Prevention Patterns

BOLA is preventable, but the prevention pattern must be enforced consistently. Four anti-patterns and their fixes:

Anti-pattern 1: Filter in the database, trust the filter.

@app.get("/invoices/{invoice_id}")
def get_invoice(invoice_id: str, user: User = Depends(current_user)):
    return db.invoices.find_one({"id": invoice_id})  # BOLA: no user check

The query is missing the predicate that constrains by user. Fix:

@app.get("/invoices/{invoice_id}")
def get_invoice(invoice_id: str, user: User = Depends(current_user)):
    invoice = db.invoices.find_one({"id": invoice_id, "tenant_id": user.tenant_id})
    if not invoice:
        raise HTTPException(404)
    authorize(user, "invoice:read", invoice)  # double-check via policy layer
    return invoice

Two layers: the database query is constrained, and the policy layer re-checks. Defence in depth.

Anti-pattern 2: GraphQL field resolvers without resolver-level auth. GraphQL trends toward “auth is per-resolver” but many implementations check at the query root and not on nested resolvers. An attacker requesting user { friends { ssn } } may pass the user-level check while accessing fields on friends that should be denied.

Anti-pattern 3: Tenant ID from the request body. If POST /api/charge {"tenant_id": "...", "amount": ...} trusts tenant_id from the body, an attacker overrides it to operate on another tenant. Fix: derive tenant_id exclusively from the authenticated session.

Anti-pattern 4: Predictable IDs. Sequential integer IDs make enumeration trivial. UUIDs reduce (but do not eliminate) enumeration risk; never substitute for actual authorisation.

Technical Deep Dive: Mass Assignment / BOPLA Prevention

BOPLA classic example: a profile-edit endpoint that accepts an arbitrary JSON body and applies it to the user object. An attacker includes a field they should not be able to set:

PATCH /users/me
Content-Type: application/json

{"display_name": "Alice", "role": "admin", "tenant_id": "victim-corp"}

Prevention patterns:

  • Allowlist DTOs. Define a per-endpoint DTO that explicitly enumerates the writable fields; reject unknown fields rather than silently ignore.
  • Per-field authorisation. The policy engine evaluates not just “can this user edit this object” but “can this user edit this field on this object.”
  • Frozen fields. Mark sensitive fields (role, tenant_id, created_by) as immutable at the framework level.

Technical Deep Dive: Policy as Code with OPA

Open Policy Agent (OPA) is the most widely deployed policy engine in 2026. The pattern: encode authorisation policy in Rego, evaluate at request time, return allow/deny + reason.

package authz

default allow := false

# Tellers can view accounts in their own branch
allow if {
    input.action == "account:read"
    input.subject.role == "teller"
    input.resource.branch_id == input.subject.branch_id
}

# Branch managers can read all accounts in their branch and approve transfers up to 5L
allow if {
    input.action == "account:read"
    input.subject.role == "branch_manager"
    input.resource.branch_id == input.subject.branch_id
}

allow if {
    input.action == "transfer:approve"
    input.subject.role == "branch_manager"
    input.resource.amount <= 500000
}

# Compliance can read any account but only via audit interface
allow if {
    input.action == "account:read"
    input.subject.role == "compliance"
    input.context.client == "audit-portal"
}

The policy is versioned, tested, deployable independently of application code, and provides an auditable record of authorisation decisions.

Technical Deep Dive: ReBAC with OpenFGA

For collaborative or sharing-heavy applications, ReBAC expresses authorisation more naturally:

model
  schema 1.1

type user

type organization
  relations
    define member: [user]
    define admin: [user]

type project
  relations
    define organization: [organization]
    define viewer: [user] or member from organization
    define editor: [user] or admin from organization
    define owner: [user]

type document
  relations
    define project: [project]
    define viewer: [user] or viewer from project
    define editor: [user] or editor from project

Asking “can Alice edit document D?” traverses the relationship graph: is Alice an editor of D directly? Is she an editor of D’s project? Is she an admin of D’s project’s organization? OpenFGA / SpiceDB evaluate these in milliseconds against an authorisation graph stored separately from application data.

Practical Implementation: A Secure API Scaffold

Defaults that prevent the most common bugs:

  • Default deny. The HTTP framework rejects any endpoint that does not declare an explicit authorisation policy.
  • Implicit tenant scoping. A request context object derived from the JWT carries tenant_id; the ORM layer auto-injects it into every query.
  • DTO-only request binding. Endpoints accept typed DTOs; arbitrary JSON binding is forbidden.
  • Standard rate limiting. Per-IP and per-token rate limits by default; per-endpoint overrides for expensive operations.
  • Response envelope. A response wrapper that strips sensitive fields by default unless explicitly opted in.
  • Audit logging. Every authorisation decision logged with subject, action, resource, decision, reason.

Technical Deep Dive: Testing

Authorisation tests must cover the negative space — what should not be allowed. Test patterns:

  • Cross-tenant access. Authenticate as tenant A, attempt to access tenant B’s resources; expect 404 or 403.
  • Cross-user same-tenant. Authenticate as user X in tenant A, attempt user Y’s resources; expect denied.
  • Role escalation via mass assignment. Non-admin user attempts PATCH with admin fields; expect denied or fields ignored.
  • Method-tampered access. If GET is allowed, attempt DELETE; expect denied.
  • API version drift. v1 may have stricter checks than v2; test both.
  • Indirect access via search. Listing endpoints sometimes return resources the user cannot fetch directly; test for leakage.

Tools for automated API authorisation testing: Burp Suite Professional with Autorize extension, ZAP with Authentication add-on, Akto, Escape DAST. Schemathesis for property-based testing of OpenAPI schemas.

Enterprise Use Cases

Indian fintech open APIs. Account Aggregator framework APIs, UPI extensions, Bharat Connect — all are externally callable and require BOLA-clean implementations. The DPDP Section 8(5) safeguard requirement now includes evidence of authorisation testing.

SaaS APIs. Multi-tenant SaaS vendors are the primary BOLA target. ReBAC with OpenFGA is the architecturally cleanest answer for collaborative products.

Public-sector portals. Citizen-facing APIs (DigiLocker, e-Gov platforms) handle high-value identity data and need especially rigorous authorisation testing because the data sensitivity is severe and the user volume is large.

Common Pitfalls

  • Authentication treated as authorisation. “User is logged in” is not “user is allowed to do this.”
  • UI-side authorisation only. The button is hidden; the API endpoint is open. Trivial to discover via OpenAPI spec or directory enumeration.
  • JWT claims trusted without verification. Claims in the JWT are only as trustworthy as the signature; verify signature, expiration, audience, issuer.
  • Internal endpoints exposed. “Admin” microservices reachable from the public ingress because someone forgot the ingress rule.
  • No tests for negative cases. Tests verify that the right user can do the right thing; the wrong user trying the same thing is rarely tested.

Action Items

  • Pick your highest-traffic API; instrument it with structured authorisation logging; review who is calling what.
  • Write five BOLA test cases against your most sensitive endpoint family; run them in CI.
  • Audit DTO usage: how many endpoints accept arbitrary JSON?
  • Inventory undocumented endpoints (the GraphQL introspection trick, the Swagger leak).
  • Evaluate OPA or OpenFGA for one upcoming feature instead of inline checks.
  • Adopt automated DAST against staging APIs on every release.

API security is principally an authorisation problem in 2026, and authorisation is principally an engineering-discipline problem. The codebases that prevent BOLA at scale are the ones with secure-by-default scaffolding and a culture that treats missing authorisation as a P0 bug.

Need a real pentest?

Get a VAPT scoping call

Senior practitioner-led VAPT — not a checklist run by juniors. CVSS-scored findings, free retest, attestation letter. India's SMBs and SaaS teams.

Book VAPT scoping call Replies in 4 working hrs · India-only · Senior consultants