Last updated: May 18, 2026
What’s in the 2026 draft
OWASP API Top 10 — 2026 dropped as a working draft in April. The list reorganises around how attackers actually exploit API estates in 2026, not how reviewers theoretically classify findings. Two new entries, one renamed, two consolidated. If you wrote your API security programme around the 2023 list, here is what changes and what it means in an Indian fintech reality.
The 2023 → 2026 delta
| 2023 entry | 2026 movement |
|---|---|
| API1: BOLA | Stays — still #1 by frequency in Indian VAPT engagements |
| API2: Broken Authentication | Renamed “Identity & Session Failures”; absorbs JWT misuse explicitly |
| API3: BOPLA | Stays |
| API4: Unrestricted Resource Consumption | Stays; new sub-class for LLM token spend |
| API5: BFLA | Stays |
| API6: Unrestricted Access to Sensitive Business Flows | Stays; expanded to cover replay-by-design flows |
| API7: SSRF | Stays |
| API8: Security Misconfiguration | Folded into a broader “Configuration & Supply Chain” entry |
| API9: Improper Inventory Management | Stays; renamed “Asset & Version Drift” |
| API10: Unsafe Consumption of APIs | Replaced by “Agentic/AI API Consumption” |
Why BOLA stays at #1 in Indian fintech — the canonical bug
Broken Object Level Authorization — the bug where /accounts/123/transactions lets the holder of account 124 read account 123’s data because the server only checks the bearer token, not whether that token belongs to the account owner — is the single most common high-severity finding in our Indian fintech engagement history. The reason is structural. Most Indian fintech APIs grew out of a single-tenant origin — one app, one user, one account — and authorisation became “is the JWT valid” rather than “does this principal own this object.” When the product grew into multi-account or partner-broker territory, the authorisation logic did not get refactored. BOLA findings result.
The canonical broken code, in Express:
// Broken: the route trusts the path parameter, not the caller's identity
app.get('/accounts/:id/transactions', requireAuth, async (req, res) => {
const txns = await db.transactions.findAll({ where: { accountId: req.params.id } });
res.json(txns);
});
// Attacker with a valid JWT for account 124 simply curls
// /accounts/123/transactions
// and reads account 123's data. requireAuth checks the token is valid;
// nothing checks that the token's subject owns account 123.
The invariant-based fix:
// 1. State the ownership predicate once
async function callerOwnsAccount(req, accountId) {
return await db.account_principal.exists({
accountId,
principalId: req.auth.subject,
revokedAt: null,
});
}
// 2. Enforce it on every handler that touches an account-scoped object
app.get('/accounts/:id/transactions', requireAuth, async (req, res) => {
if (!(await callerOwnsAccount(req, req.params.id))) return res.sendStatus(404);
const txns = await db.transactions.findAll({ where: { accountId: req.params.id } });
res.json(txns);
});
// 3. Test the negative path. This is the test that catches the regression
// when somebody adds a new route and forgets the predicate.
test('GET /accounts/:id/transactions denies non-owner', async () => {
const tokenA = await login('userA');
const accountB = await fixtures.createAccountOwnedBy('userB');
const res = await fetch(`/accounts/${accountB.id}/transactions`,
{ headers: { authorization: `Bearer ${tokenA}` } });
expect(res.status).toBe(404);
});
Return 404, not 403 — the existence-leak matters in financial contexts. The negative test is the part most teams skip; the positive test (owner can read) gives false confidence.
API2 / Identity & Session Failures — the JWT algorithm-confusion case
The 2026 list calls out JWT misuse explicitly. The classic failure mode that still appears in pentests:
# Server signs JWTs with RS256 (RSA public/private key pair)
# Server validation code accepts "any algorithm the token claims"
jwt.decode(token, public_key) # uses the alg from the token header — BROKEN
# Attacker takes the public key (it is, by definition, public),
# re-encodes the token with alg=HS256, signs it with the public key as the HMAC secret,
# and the server accepts it because HS256 with public_key happens to match.
# The attacker now mints any token they want.
The fix is to pin the expected algorithm:
jwt.decode(token, public_key, algorithms=["RS256"]) # pin the alg
Two-line change, library-level. Every major JWT library has the option. Many production deployments still do not use it. Test for it: take any token your service issues, decode the header, set alg=none and resign with an empty signature. If the server accepts it, you are exposed. We have observed this exact bug in 4 of the last 30 fintech engagements.
API4 / LLM token-spend amplification
The 2026 text formalises a class of bug that started appearing in late 2024: an unauthenticated or low-privilege endpoint that triggers an LLM call you pay for, with no rate limit and no token budget. The attack is not data exfiltration — it is making your AWS Bedrock or OpenAI bill go up 200x in a weekend.
# Vulnerable: no per-caller rate limit, no max-tokens cap
@app.post("/summarize")
def summarize(text: str):
return openai.chat.completions.create(
model="gpt-4o",
messages=[{"role":"user","content":f"Summarize: {text}"}],
)
# Attacker scripts curl -X POST -d "$(yes 'a' | head -c 50000)" /summarize x 1000.
# 50M input tokens at $3/1M = $150 in one weekend, no signup.
The defence is layered: rate-limit per IP and per authenticated principal; cap max-tokens in both directions; charge against a daily budget per tenant; alert on per-tenant spend >3σ of baseline. The 2026 list treating this as a first-class API4 sub-class is a recognition that LLM-backed endpoints have economics that change the threat model.
API10 / Agentic AI consumption — the new failure modes
The 2023 API10 was about your service’s risk from third-party APIs you call. The 2026 API10 widens this to include the case where your service is consumed by AI agents that act on behalf of users. Two new failure modes appear in the 2026 text.
First, action composition. Permitted operations chained into an unintended privileged action. A simple example: the customer-service agent can read the customer’s address and the customer can update their address. The agent composes “read user’s address, then update it” — and now the agent can move a user’s account to an attacker-controlled address by social-engineering a single chat exchange. Each individual operation is permitted; the composition is not, but no API enforces composition limits.
Second, identity-of-actor. An agent authenticates as the user but acts independently. Your audit log records “user X did Y” — true at the token level, false at the cognitive level. Disputed transactions become impossible to attribute. The defensive pattern is to require the agent to assert its identity in a non-spoofable way at the API boundary, and to log both the user and the agent on every privileged operation:
# Standard token: identifies the user
Authorization: Bearer eyJhbGciOiJSUzI1NiIs...
# New: agent identity, signed by the agent platform's key (e.g. RFC 9449 DPoP)
DPoP: eyJ0eXAiOiJkcG9wK2p3dCI...
X-Acting-Agent: claude-customer-service-bot
X-Agent-Session: 6f3a...
# Server logs both. Audit log entry:
# user=u_8429 agent=claude-customer-service-bot action=address_update …
Indian neo-banks and brokers integrating with AI assistants for customer query-handling are exposed here. The defensive controls are not yet standardised — DPoP is the closest analogue — but the principle is “log the cognitive actor, not just the cryptographic principal.”
What changes in a pentest scope
- Add a JWT/session sub-checklist under API2. The 2026 text makes the algorithm-confusion, weak-signing-key, and key-rotation classes explicit.
- Include LLM-cost-amplification tests under API4 if your API has an LLM-backed endpoint.
- Test agentic consumption patterns under API10 if you integrate with any AI assistant platform.
- The Asset & Version Drift rename is a hint — make sure your inventory script catches stale API versions, deprecated-but-online endpoints, and shadow APIs that grew out of partner integrations.
- Build BOLA tests as a category, not a finding type. Every account-scoped route gets a positive test (owner can read) AND a negative test (non-owner cannot).
Public comment closes 30 June 2026
The 2026 list is a draft until the OWASP Project Committee finalises it later this year. If you have field data — counts of findings by category from real engagements — the project welcomes anonymised submissions. India is consistently under-represented in the OWASP datasets that drive these lists; if you are running an Indian AppSec programme with reasonable telemetry, your data shifts the global picture.
References
- RingSafe Academy track: API Security Deep Dive
- RingSafe Academy track: Web Application Penetration Testing
- RingSafe Academy track: Attacker Mindset — Web
- OWASP API Security Project — owasp.org/www-project-api-security
- RFC 9449 — OAuth 2.0 Demonstrating Proof of Possession (DPoP)
Related engagement → How we ran a web app pentest for a leading Indian fintech
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.