Developer Exposes 12 Vulnerabilities in FastAPI Todo App After 176 Bots Bypass Protections

A developer building a student-focused todo planner on FastAPI discovered that 176 of 238 new accounts were bots that bypassed three layers of protection including rate limiting and email verification. The issues stemmed from in-memory counters reset on every deployment, uvicorn trusting any X-Forwarded-For header, and email verification never being enforced in code. A full audit revealed additional flaws such as stored XSS via JSON-LD on public Q&A pages and an IDOR allowing any authenticated user to read all tasks in a project by supplying its ID. Fixes included moving rate limits to the database, properly extracting the client IP from the rightmost X-Forwarded-For entry, adding signed form timestamps, and escaping JSON for script contexts. The case highlights common pitfalls when deploying Python web services behind nginx without strict trust boundaries.

HabrTranslated from Russian

Read at source

A Russian developer who started with a simple FastAPI todo list four months ago ended up running a multi-product platform and uncovering a dozen security issues after bots flooded the registration form.

The service at getdoday.ru grew to include a planner for schoolchildren, a Q&A module, a traffic-ticket trainer, and a tutor dashboard, all inside one 86,000-line monolith with 1,325 tests. Within two weeks the database showed 238 new accounts; only 62 confirmed their email. The remaining 176 were bots using disposable domains such as sdffsd.sdd and prweorwef.com.

Bots bypassed three protection layers

The original defenses were a honeypot field, a five-registrations-per-minute IP limit, and email confirmation. None worked. The rate limiter used an in-memory deque that was cleared on every deployment; with dozens of commits per day the counter effectively never existed. uvicorn was started with --forwarded-allow-ips='*', causing it to trust the leftmost IP supplied in the X-Forwarded-For header. An attacker could therefore rotate a fake address on every request and never hit the limit. Email verification set a timestamp but the column was never checked anywhere in the authorization logic.

Instead of adding hard email gates that would hurt real users behind school NATs, the developer implemented three lightweight checks: a signed timestamp proving the form was rendered at least a few seconds earlier, hourly registration counters stored in the database with separate per-subnet limits, and a DNS lookup confirming the mail domain actually exists.

Stored XSS via JSON-LD and an IDOR

During the subsequent full audit twelve additional vulnerabilities were found. Public Q&A pages rendered user-supplied question titles inside a JSON-LD script block using the safe filter. Because the HTML parser does not understand JSON, an attacker could close the script tag and inject executable code that exfiltrated the victim’s entire account export.

Another flaw allowed any logged-in user to read every task belonging to a project simply by supplying its UUID to the /api/tasks endpoint; membership checks existed only on the HTML page, not inside the service layer.

Other issues included an inability to invalidate sessions after password change and rate-limit bypasses on multiple endpoints. All findings were addressed with tests and the developer published the complete post-mortem on Habr.

Meridian digestThe week's most consequential security stories, distilled into one briefing.See the digest

More in Vulnerabilities & Exploits

Telegram for Android Patches Voice Call Vulnerability Enabling Code Execution
Yandex Patches Millions of Stations After eMudhra Certificate Keys Compromised
Cisco ASA and FTD Face DoS Vulnerability in SSL VPN Already Exploited in the Wild