Skip to main content

API Vulnerabilities Lab

1. Broken Object Level Authorization (BOLA)

Also known as IDOR, highly prevalent in APIs. (Covered similarly in the Web Lab, ensure authorization checks validate object ownership against the current user context.)

2. Mass Assignment

Vulnerable Code

from pydantic import BaseModel

class UserUpdate(BaseModel):
# VULNERABLE: Allowing modification of sensitive fields like 'is_admin'
email: str
is_admin: bool = False

@app.put("/users/{user_id}")
def update_user(user_id: int, user_data: UserUpdate):
user = db.query(User).filter(User.id == user_id).first()
# Blindly updating all fields from the input request
for key, value in user_data.dict().items():
setattr(user, key, value)
db.commit()
return user

Exploit Script

import requests

url = "http://localhost:8000/users/5"
# Payload injecting the 'is_admin' field to escalate privileges
payload = {"email": "attacker@example.com", "is_admin": True}
headers = {"Authorization": "Bearer <user_token>"}
response = requests.put(url, json=payload, headers=headers)
print(response.json())

Secure Fix

class SafeUserUpdate(BaseModel):
# SECURE: Explicitly define only allowed fields
email: str

@app.put("/users/{user_id}")
def update_user(user_id: int, user_data: SafeUserUpdate):
user = db.query(User).filter(User.id == user_id).first()
user.email = user_data.email
db.commit()
return user

3. Token Manipulation (JWT Null Signature)

Vulnerable Code

import jwt

@app.get("/secure-data")
def get_secure_data(token: str):
# VULNERABLE: Not verifying the signature or accepting 'none' algorithm
try:
decoded = jwt.decode(token, options={"verify_signature": False})
return {"data": "Secret API data"}
except Exception:
return {"error": "Invalid token"}

Exploit Script

import jwt
import requests

# Creating a forged token with 'none' algorithm
forged_token = jwt.encode({"user": "admin"}, key="", algorithm="none")

url = f"http://localhost:8000/secure-data?token={forged_token}"
response = requests.get(url)
print(response.json())

Secure Fix

@app.get("/secure-data")
def get_secure_data(token: str):
# SECURE: Enforce strong algorithm and verify signature
try:
decoded = jwt.decode(token, key="supersecretkey", algorithms=["HS256"])
return {"data": "Secret API data"}
except jwt.PyJWTError:
return {"error": "Invalid token"}
Share this guide