1. Section Goal
This section covers API security issues beyond basic BOLA/BFLA.
Main focus:
Login/user enumeration
Password reset token weakness
OTP brute force
Token lifecycle issues
Token in URL
JWT tampering
Deprecated/old APIs
Webhook security
GraphQL security
Business logic abuse
Shadow/undocumented APIs
2. Login User Enumeration
What it is
User enumeration happens when the application reveals whether a username/email exists.
Example:
Existing email + wrong password → 401 Invalid password
Non-existing email → 404 User not found
This tells attacker which email is valid.
Why it is a problem
Attacker can build a valid user list and then perform:
Credential stuffing
Password brute force
Phishing
Targeted account takeover attempts
Root cause
The backend gives different responses for different failed login cases.
Correct fix
For every failed login attempt, return same generic response.
Example:
Invalid credentials
Also add:
Rate limiting
Account lockout/throttling
Monitoring
MFA/risk-based challenge
Same timing behavior as much as possible
Memory line
Login errors should not reveal whether email or password was wrong.
3. Weak Password Reset Token
What it is
Password reset token is weak, guessable, long-lived, reusable, or not rate-limited.
Example:
https://app.example.com/reset-password?token=123456
Issues:
6-digit token
Valid for 24 hours
Unlimited attempts
Reusable
Not bound to user/session
Why it is a problem
Attacker can brute force or guess reset tokens and reset another user’s password.
Impact:
Account takeover
Privilege escalation if admin account is targeted
Loss of user trust
Root cause
Poor reset token design and missing server-side controls.
Correct fix
Password reset token should be:
Long
Cryptographically random
Short-lived
Single-use
User-bound
Stored hashed server-side
Rate-limited per user/IP/token
Important note:
Password reset tokens in URL are common and not automatically wrong. The issue is when the token is weak, long-lived, reusable, logged, or not rate-limited.
Memory line
Reset token = long, random, short-lived, single-use, user-bound, rate-limited.
4. OTP Brute Force / Missing Rate Limiting
What it is
OTP is valid, but backend allows unlimited attempts.
Example:
6-digit OTP
Valid for 10 minutes
No attempt limit
No rate limit
Why it is a problem
6-digit OTP has limited combinations.
If there is no attempt control, attacker can automate guesses.
Root cause
Backend does not enforce attempt limits, throttling, or lockout.
Correct fix
Limit OTP attempts
Rate limit per user/IP/session/device
Short OTP expiry
OTP should be random
OTP should be one-time use
Invalidate old OTP when new OTP is generated
Monitor failed attempts
Memory line
6-digit OTP is fine only with strict attempt limit, expiry, and one-time use.
5. Token Lifecycle / Missing Revocation
What it is
Access token remains valid even after:
Logout
Password change
Account disabled
Session terminated
Example:
Access token valid for 7 days.
User logs out.
Same old token still works.
Why it is a problem
If attacker steals the token, they can continue using it even after user/admin tries to stop access.
Impact:
Session hijacking
Account takeover continuation
Failed incident response
Disabled users still accessing APIs
Root cause
Backend only checks token signature/expiry, but does not check current session/user state.
Correct fix
Use short-lived access tokens
Use refresh token rotation
Maintain revocation/session store
Invalidate token after logout
Invalidate token after password change
Reject token if user is disabled
Use token/session version
Check
password_changed_atMonitor suspicious token use
Memory line
JWT signature valid does not mean session should still be trusted.
6. Access Token in URL
What it is
Bearer access token is passed in URL query parameter.
Example:
GET /api/v1/reports/export?access_token=eyJhbGciOi...
Why it is a problem
URLs leak easily into:
Browser history
Bookmarks
Referrer headers
Proxy logs
CDN logs
Web server access logs
Application logs
Analytics tools
Screenshots/shared links
If token leaks, attacker can replay it.
Root cause
Insecure token handling.
Correct fix
For API authentication:
Authorization: Bearer <token>
Also:
Do not put bearer tokens in URL
Redact tokens from logs
Use short-lived tokens
Rotate/revoke exposed tokens
Avoid logging authorization secrets
Important distinction
Access token should normally go in Authorization header.
Password reset token can be in URL if it is strong, short-lived, single-use, and user-bound.
Short-lived signed download URLs can be acceptable if scoped and time-limited.
Memory line
Bearer access token in URL = token leakage risk. Use Authorization header.
7. JWT Tampering / Missing Signature Validation
What it is
Attacker modifies JWT claims and backend accepts modified token.
Example:
Original token payload:
{
"user_id": "1001",
"role": "user"
}
Modified token payload:
{
"user_id": "1001",
"role": "admin"
}
If backend accepts this, JWT validation is broken.
Why it is a problem
Attacker can modify:
Role
User ID
Tenant ID
Permissions
Scope
Impact:
Privilege escalation
Cross-user access
Cross-tenant access
Admin access
Root cause
Backend is trusting decoded JWT claims without verifying signature and expected claims.
Correct fix
Backend must validate:
Signature
Expected algorithm
Expiry:
expIssuer:
issAudience:
audTenant/user/session state
Role/permission on backend
Reject:
Unsigned tokens
Tampered tokens
Unexpected algorithms
Expired tokens
Wrong issuer/audience
Memory line
JWT can be decoded by anyone; it is trusted only after signature and claims are validated.
8. Deprecated / Old API Exposure
What it is
Old API version is still reachable and has weaker security controls.
Example:
/api/v2/reports/export → 403 for normal user
/api/v1/reports/export → 200 and downloads all reports
Why it is a problem
Attacker bypasses the secured new API by directly calling old API.
Impact:
Unauthorized data export
Access control bypass
Sensitive data exposure
Compliance/privacy issue
Root cause
Poor API lifecycle management.
Common causes:
Old API not removed
Old API not secured like new API
Poor inventory
Legacy clients still using old API
Security testing focused only on current UI/API
Correct fix
Enforce same authorization on old API immediately
Deprecate/remove old API if not required
Maintain complete API inventory
Monitor legacy endpoint usage
Migrate old clients
Include old APIs in testing
Block old endpoints at gateway if obsolete
Memory line
Old API is not automatically vulnerable; old API with weaker controls is the issue.
9. Webhook Security
What is a webhook
Webhook is automatic server-to-server communication.
Example:
Payment provider backend → Application backend
Webhook means:
Third-party system tells your backend that an event happened.
Examples:
Payment successful
Refund processed
Shipment delivered
GitHub code pushed
User created in identity provider
Payment webhook example
POST /api/payment/webhook
{
"order_id": "ORD-1001",
"status": "paid",
"amount": 5000
}
What is the vulnerability
Backend accepts webhook body without verifying it came from real provider.
Example attack:
Attacker/Postman/Burp → /api/payment/webhook
status=paid
Backend marks order as paid.
Why it is a problem
Attacker can:
Mark unpaid order as paid
Trigger shipment/service activation
Manipulate amount/status/order ID
Replay old webhook
Cause direct business loss
Root cause
Missing webhook trust validation.
Backend does not validate:
Provider signature
Timestamp freshness
Event ID uniqueness
Order ID
Amount
Currency
Payment status
Provider transaction ID
Correct fix
Backend should:
Verify webhook signature using provider secret.
Verify timestamp freshness.
Store and process event ID only once.
Match order ID, amount, currency, and status with backend records.
Optionally verify transaction directly with provider API.
Reject unsigned/invalid/replayed requests.
Log and monitor suspicious webhook attempts.
Proxy clarification
Real webhook is backend-to-backend, so user browser/Burp proxy usually should not see full provider webhook traffic.
User may see:
Payment successful
Order confirmed
Receipt generated
But normally should not see:
X-Signature
X-Timestamp
Webhook event ID
Full provider callback headers
Webhook secret
If full webhook details appear in browser/mobile proxy, investigate further.
Important distinction
Seeing order ID/payment status in frontend is not automatically a vulnerability.
It becomes vulnerable if backend trusts client-controlled payment status or unsigned webhook data.
Memory line
Webhook body is untrusted until signature, timestamp, event ID, and business values are verified.
10. GraphQL Security
What is GraphQL
GraphQL usually exposes one endpoint:
POST /graphql
Instead of many REST endpoints, client sends query/mutation inside the request body.
Example query:
query {
user(id: "123") {
name
email
}
}
Example mutation:
mutation {
updateUserRole(userId: "456", role: "admin")
}
What is introspection
Introspection lets user ask GraphQL:
What queries exist?
What mutations exist?
What fields exist?
What arguments are required?
It is useful for developers and tools.
Security view on introspection
In production, public unauthenticated introspection should generally be disabled or tightly restricted.
Why?
Because it exposes the API map:
Hidden mutations
Admin operations
Internal object names
Sensitive fields
Deprecated operations
Argument names
But introspection is not the main vulnerability
Introspection reveals what exists.
Authorization controls who can use it.
Even if introspection is disabled, attacker may discover mutations through:
JavaScript files
Mobile app traffic
Old docs
GraphQL errors
Postman collections
Leaked schema
Guessing
What is resolver authorization
In GraphQL, each query or mutation is handled by a backend function called a resolver.
Example:
updateUserRole mutation → updateUserRole resolver/function
resetPassword mutation → resetPassword resolver/function
getUser query → getUser resolver/function
Resolver authorization means:
Before executing the resolver, backend checks whether logged-in user is allowed to perform that action.
Example checks:
Is user authenticated?
Is user admin?
Can this admin update this user?
Is target user in same tenant?
Is requested role change allowed?
Vulnerable example
mutation {
updateUserRole(userId: "456", role: "admin")
}
Normal user sends this manually and it succeeds.
Why it is a problem
Impact:
Privilege escalation
Account takeover
Admin access
Tenant compromise
Root cause
Missing resolver-level authorization.
UI hides the action, but backend still allows it.
Correct fix
Enforce authorization on every resolver
Sensitive mutations require admin permission
Tenant checks on objects
Do not rely on UI hiding
Disable/restrict introspection in production
Add audit logs for sensitive mutations
Add rate limiting/monitoring
Memory line
Introspection reveals what exists. Resolver authorization controls who can use it.
11. Business Logic / API Abuse
What it is
A request is technically valid, but it violates business rules.
Example:
POST /api/v1/apply-coupon
{
"cart_id": "CART-1001",
"coupon_code": "WELCOME50"
}
Business rule:
WELCOME50 can be used only once per user.
But attacker sends same request repeatedly and discount applies again and again.
Why it is a problem
Attacker can:
Reduce cart value repeatedly
Get products for very low or zero price
Abuse coupons/promotions
Cause direct business loss
Automate abuse across accounts
Root cause
Backend does not enforce business rule or state validation.
Missing checks:
Has user already used this coupon?
Is coupon already applied to this cart?
Is coupon valid for this user?
Is discount within allowed limit?
Is cart total recalculated server-side?
Correct fix
Enforce coupon rules server-side
Bind coupon usage to user/account
Prevent duplicate application on same cart
Mark coupon as used after successful use
Recalculate discount server-side
Add transaction/locking to prevent race conditions
Monitor abuse patterns
Memory line
Business logic flaw = request is valid technically, but violates business rules.
12. Shadow / Undocumented API
What it is
API endpoint exists but is not documented, not visible in UI, or not included in normal testing/inventory.
Example:
GET /api/internal/admin/export-all-users
Normal user token returns all users.
Why it is a problem
Undocumented APIs may be missed from:
Security testing
Monitoring
Access-control review
API inventory
Gateway policy enforcement
Documentation
Important correction
Undocumented does not automatically mean vulnerable.
The issue is:
Undocumented/internal API + weak/missing authorization
Impact
Attacker can:
Discover hidden endpoints from JS/mobile/docs/logs
Access internal/admin functions
Export user data
Dump emails, names, roles, tenant info
Cause privacy/compliance issue
Root cause
Incomplete API inventory
Internal endpoint publicly reachable
Missing backend authorization
Sensitive routes exposed in JavaScript
Poor API governance
Endpoint excluded from security review
Correct fix
Enforce authorization on undocumented/internal APIs
Return 403 for normal users
Remove or restrict internal APIs
Maintain complete API inventory
Include all APIs in testing
Review JS/mobile apps for hidden routes
Monitor access to sensitive export endpoints
Apply gateway controls consistently
Memory line
Undocumented does not automatically mean vulnerable; undocumented plus weak authorization is the issue.
13. Quick Classification Table
| Scenario | Correct classification |
|---|---|
| Different login errors reveal valid email | User enumeration |
| 6-digit reset token, no rate limit | Weak password reset token |
| OTP has unlimited attempts | OTP brute force / missing rate limiting |
| Token works after logout/password change/disable | Poor token lifecycle / missing revocation |
| Access token in URL | Insecure token handling |
| JWT role changed to admin and accepted | JWT validation failure |
| v1 old API bypasses v2 authorization | Deprecated API with weak authorization |
| Fake payment webhook marks order paid | Missing webhook signature validation |
| GraphQL admin mutation works for normal user | Missing resolver-level authorization |
| Coupon applied repeatedly | Business logic flaw / API abuse |
| Hidden internal API exports all users | Shadow API with broken authorization |
14. Common Interview Answer Template
Use this structure:
1. This is <vulnerability name>.
2. The backend is trusting <client input/token/object/action/webhook> without validating <authz/signature/state/business rule>.
3. Attacker can <real impact>.
4. Root cause is missing server-side <control>.
5. Fix is <specific backend control>, not only frontend/UI restriction.
Example:
This is an insecure webhook implementation. The backend trusts the webhook body without verifying that it came from the real payment provider. An attacker can send a fake payment confirmation and mark unpaid orders as paid. The root cause is missing signature, timestamp, replay, and business validation. The fix is to verify provider signature, check timestamp freshness, process event ID only once, and match order ID, amount, currency, and status with backend records.
15. Section 3 Final Memory Pack
Login errors should not reveal valid users.
Reset token = long, random, short-lived, single-use, user-bound, rate-limited.
6-digit OTP is acceptable only with strict attempt limits and expiry.
JWT signature valid does not mean session should still be trusted.
Bearer access tokens should not be placed in URLs.
JWT can be decoded by anyone; trust only after signature and claims validation.
Old API is not automatically vulnerable; old API with weaker controls is the issue.
Webhook body is untrusted until signature, timestamp, event ID, and business values are verified.
Webhook = third-party backend automatically calls your backend when an event happens.
GraphQL introspection reveals what exists; resolver authorization controls who can use it.
Business logic flaw = technically valid request violates business rules.
Undocumented API is not automatically vulnerable; undocumented plus weak authorization is the issue.
Dangerous body field accepted = mass assignment.
Normal user calling admin function = BFLA.
Wrong object ID access = BOLA.
Tenant check first, then user/role/object permission check.
Comments
Post a Comment