API Rate Limiting for Patient Portals: Stopping Abuse Early
Credential stuffing, account enumeration and scraping all look like ordinary traffic one request at a time. Rate limiting is what makes the pattern visible and expensive.
GuardsArm Team
Security Experts
A single login attempt is indistinguishable from a legitimate one. Ten thousand of them, spread across accounts, is credential stuffing. Rate limiting is the control that turns that volume into something you can see and refuse — and on a patient portal it is doing more work than almost anything else.
Limit per endpoint, not globally
A single global limit is either too loose to stop abuse or too tight for normal use. Different endpoints carry different risk and need different budgets.
| Endpoint | Suggested limit | Rationale |
|---|---|---|
| Login | 5 per account per 15 min, 20 per IP per 15 min | Stops stuffing without locking out a fumbling patient |
| Password reset request | 3 per account per hour | Prevents reset-flood harassment |
| Registration / enrolment | 3 per IP per hour | The enrolment attack surface — see below |
| Record retrieval | 60 per session per hour | Generous for a person, restrictive for a scraper |
| Bulk document download | 10 per session per hour | Legitimate use is small |
| Search / lookup | 30 per session per hour | Classic enumeration endpoint |
| Message send | 20 per session per hour | Abuse and spam control |
Enrolment deserves particular attention, because portal compromise more often defeats registration than login — covered in patient portal security.
What to key the limit on
Keying on IP alone fails in both directions: it punishes a hospital's own NAT gateway and it does nothing against a botnet.
Distributed attacks need a different answer
An attacker with a thousand IPs each making five requests defeats per-IP limiting entirely, and never trips a per-account limit if they are spraying one password across many accounts.
What catches it:
- Global anomaly detection — total login failures across the portal, not per source. A step change in the aggregate is the signal.
- Password spraying detection — many accounts, one password, low per-account volume. Detect on the failure pattern, not the rate.
- Reputation and bot management for known-bad infrastructure.
- Adaptive friction — introduce a challenge when the aggregate failure rate rises, rather than blocking outright.
Failing gracefully
How you respond matters as much as when:
- Return 429 with a
Retry-Afterheader, not a generic 500 - Exponential backoff rather than a hard lockout, which is itself a denial-of-service against your own patients
- Never lock permanently on failed logins; an attacker will lock every account they can name
- Log every limit breach with enough context to investigate
- Alert on the aggregate, not on individual events
Do not break legitimate integrations
Patient portals increasingly serve third-party applications over FHIR, and those clients behave nothing like a browser. A health app syncing a year of records makes a burst of requests that looks exactly like scraping.
Treat them separately: authenticated API clients get their own registered identity, their own quota appropriate to the integration, and their own monitoring. Applying browser-shaped limits to a sanctioned FHIR client breaks it, and the usual fix — raising the global limit — removes the protection for everyone.
GuardsArm tests patient portals and their APIs including rate limit bypass, enumeration and distributed credential attacks. Book a scoping call.
Written by GuardsArm Team
Our team of cybersecurity experts brings decades of combined experience in penetration testing, compliance auditing, and incident response. We're dedicated to helping organizations strengthen their security posture.
Take the next step on “API Rate Limiting for Patient Portals: Stopping Abuse Early”
Talk to the GuardsArm team about how these services apply to your environment.


