All Docs
FeaturesMaking Tax DigitalUpdated February 27, 2026

Security: Rate Limiter IP Spoofing Bypass (v1.0.154)

Security Advisory: Rate Limiter IP Spoofing Bypass

Release: v1.0.154
Severity: High
Component: src/lib/rate-limit.ts


Summary

A vulnerability was identified in the in-memory rate limiter where client-controlled HTTP headers were trusted as the authoritative source of the client's IP address. This allowed an attacker to bypass all IP-based rate limits by sending forged header values — with no server-side validation of whether those values were legitimate.


Affected Endpoints

EndpointRate LimitImpact of Bypass
HMRC OAuth flow5 requests / minuteEnables automated OAuth abuse, token farming, or denial-of-service against the HMRC integration
Feedback endpoint3 requests / minuteEnables spam or abuse of the feedback pipeline
Unauthenticated tRPC mutations20 requests / minuteEnables brute-force or enumeration attacks on public mutation endpoints

The HMRC OAuth endpoint is the highest-risk surface: it is rate-limited specifically to prevent automated abuse of the Making Tax Digital OAuth flow, and a full bypass of that limit undermines that protection entirely.


Root Cause

The rate limiter determined a client's identity by reading, in order:

  1. x-forwarded-for
  2. cf-connecting-ip
  3. x-real-ip

All three of these headers can be set arbitrarily by an HTTP client. When deployed behind a proxy or CDN (such as Vercel's edge network), the actual client IP is injected by the infrastructure — but if the application reads these headers without first stripping or validating client-supplied values, an attacker can simply include their own x-forwarded-for header to impersonate any IP and reset their rate limit window on every request.

# Example of bypass — attacker rotates header value each request
curl -H "X-Forwarded-For: 1.2.3.4" https://app.example.com/api/hmrc/oauth
curl -H "X-Forwarded-For: 5.6.7.8" https://app.example.com/api/hmrc/oauth
curl -H "X-Forwarded-For: 9.10.11.12" https://app.example.com/api/hmrc/oauth
# Each request is treated as a different IP — rate limit never triggers

Remediation

1. Use Vercel's Edge-Injected IP Header

On Vercel, the x-real-ip header is set by the edge infrastructure and cannot be overridden by the client. Use this as the sole source of IP identity:

// Preferred on Vercel
const clientIp = req.headers['x-real-ip'] as string;

Alternatively, x-vercel-ip-country is also edge-injected and can serve as a secondary signal.

2. Validate XFF Chain if Using X-Forwarded-For

If x-forwarded-for must be used, only trust the rightmost entry appended by your own trusted proxy — not the leftmost entry, which is supplied by the client:

// The rightmost IP in XFF is appended by the last trusted proxy
const xff = req.headers['x-forwarded-for'] as string;
const trustedIp = xff?.split(',').at(-1)?.trim();

This requires that your proxy configuration strips any client-supplied XFF values before appending its own.

3. Use userId-Based Rate Limiting for Authenticated Routes

For authenticated tRPC mutations, rate limiting should be keyed on the authenticated userId rather than any IP header. This is already implemented for authenticated paths and should be the exclusive control for those routes — IP-header fallback should not apply.

// For authenticated tRPC routes
const identifier = session.user.id; // not an IP header

Impact Assessment

  • Confidentiality: Low direct impact, but bypass of HMRC OAuth rate limits could facilitate credential stuffing or session abuse against HMRC-linked accounts.
  • Integrity: An attacker able to bypass the unauthenticated tRPC mutation rate limit could attempt higher-volume enumeration or mutation attacks.
  • Availability: Unrestricted request volume to rate-limited endpoints could degrade service for legitimate users.

References