In the previous article, we covered why security matters and the defense-in-depth mindset. Now it's time to break down what specific threats most commonly hit APIs. We'll use the OWASP API Security Top 10 framework — a list of the most common API threats compiled by the global security community — as our map, so that once we get hands-on, you'll know exactly which threat we're defending against at each step.
Broken Object Level Authorization (BOLA) — Threat #1
This is the MOST common API threat, and it's exactly the scenario covered in Part 1: a user can access data belonging to ANOTHER user, just by changing an ID in the request — for example GET /api/tasks/42 becomes GET /api/tasks/43, and the server never checks whether task #43 actually belongs to the currently logged-in user.
User A logs in → GET /api/tasks/42 → User A's task → OK
User A logs in → GET /api/tasks/43 → User B's task → SHOULD be rejected, but the API says OK
This is a classic authorization bug: authentication is correct (we know who's logged in), but authorization has a hole (we never check whether they're ENTITLED to that specific resource). We'll build this protection explicitly in Part 4.
Broken Authentication — Threat #2
Problems at the "proving identity" layer. Some common forms:
We fix this with correct password hashing and a JWT with a limited lifespan in Part 3, plus rate limiting in Part 4.
Excessive Data Exposure — Threat #3
The API returns MORE data than the client actually needs, on the assumption that "the frontend only displays part of it anyway." The problem: an API response can be inspected directly via browser DevTools or a tool like Postman — whatever the server sends can be seen by anyone able to intercept that response.
A concrete example: a login endpoint that returns the entire User object straight from the database, including hashed_password. Even hashed, there's no reason it needs to be sent to the client at all.
# BAD — returns the raw database object
return user # hashed_password comes along for the ride
# GOOD — an explicit response model, only the fields actually needed
class UserRead(BaseModel):
id: int
username: str
created_at: datetime
This is exactly why we've always separated the response model from the database model since the FastAPI series — it was never just about tidiness, it's about security.
Injection — Threat #4
Data sent by a user gets treated as CODE, not just data — most famously via SQL injection: if a database query is built by concatenating raw strings from user input, an attacker can smuggle in extra SQL commands.
# BAD — vulnerable to SQL injection
query = f"SELECT * FROM users WHERE username = '{username}'"
# username input: "admin' OR '1'='1" → the query always becomes TRUE, bypassing login!
# GOOD — parameterized query, input is ALWAYS treated as data
session.exec(select(User).where(User.username == username))
The good news: modern ORMs like SQLModel/SQLAlchemy, which we've used since the start of the FastAPI series, automatically use parameterized queries under the hood — we'll prove this concretely (including trying to "attack" our own API) in Part 5.
Security Misconfiguration — Threat #5
A broad category for configuration mistakes that open up gaps — not a bug in the application logic, but in how the app is deployed and configured:
*) when there's no need to.We cover and fix all of these explicitly in Part 6.
Unrestricted Resource Consumption — Threat #6
An API with no limits — no cap on how many times a user can call an endpoint within a given time window. This opens the door to brute force (trying passwords repeatedly), mass data scraping, or simply overwhelming the server until it's unresponsive for other users. We fix this with rate limiting in Part 4.
This Series vs. OWASP Threats
To make the connection clear, here's a map of the threats covered above against the hands-on article that addresses each one:
| Threat | Addressed in |
|---|---|
| Broken Authentication | Part 3 |
| Broken Object Level Authorization | Part 4 |
| Unrestricted Resource Consumption | Part 4 |
| Injection | Part 5 |
| Excessive Data Exposure | Part 5 (response models) |
| Security Misconfiguration | Part 6 |
| Vulnerabilities from third-party dependencies | Part 7 |