Member-only story
My API Was Returning Every User’s Password Hash. I Didn’t Notice for Weeks.
Why a FastAPI endpoint happily sends back fields you never meant to expose, and the one line that filters them out
The endpoint looked harmless. Fetch a user, return the user.
@app.get("/users/{user_id}")
async def get_user(user_id: int):
user = await db.get_user(user_id)
return userIt worked. It returned the user’s name, email, everything the frontend needed. Nobody looked twice.
Weeks later, someone opened the browser network tab while debugging an unrelated issue and went quiet. The JSON response for that endpoint had a field none of us wanted anyone to see.
{
"id": 42,
"username": "anna",
"email": "anna@example.com",
"password_hash": "$2b$12$Q9....",
"is_admin": true,
"internal_notes": "flagged for review"
}The password hash. The admin flag. An internal notes field. Every column on the user row, shipped straight to the client, on every single request, for weeks.
Nothing had errored. The endpoint did exactly what I told it to. The problem was that I had told it to return “the user,” and “the user” turned out to mean all of it.











