Once upon a time, I stumbled upon something interesting while poking around apps listing on hackerone. It wasn’t an RCE, it wasn’t a SQLi but just a small tweak to bypass rate limit.

The Setup
I was on PUBG’s account portal — specifically the password reset page at:
https://accounts.pubg.com/profile/password/forgot
Like most sites, PUBG had a rate limit to stop people from brute-forcing the reset form. After a few attempts, it would hit you with the dreaded:
HTTP/1.1 429 Too Many Requests {"message":"error.forgot-rate-limit"}

if the backend trusts the X-Forwarded-For header without validating it, you can trick it into thinking you’re a completely different IP address.
So I sent the exact same password reset request — but with a little twist:
- X-Forwarded-For: 127.0.0.1



HTTP/1.1 200 OK {"redirect":"/email-sent"}
Why This Worked
PUBG’s backend was using the X-Forwarded-For header to track the client’s IP for rate limiting. But here’s the problem — that header is completely user-controlled.
they trusted whatever value the client provided. This meant I could rotate that header with any fake IP and completely bypass the limit.
This same behavior existed on the /location endpoint: GET /location HTTP/1.1 X-Forwarded-For: 24.113.42.169


ChatGPT to reproducing the Issue Locally
ChatGPT did the whole reproduction — I had no idea what I was doing from this section!!!!
Sample flask app from my boss

This app runs only on localhost (127.0.0.1:8000) — meaning any outside requests must go through Nginx.
The Nginx Reverse Proxy

At this point, any request to the public server will be proxied to Flask, with X-Forwarded-For coming from Nginx.
The Test Without Spoofing:
When I made a normal request without adding any extra headers, Flask showed my real public IP: 49.156.x.x

Then, I sent the exact same request — but this time I manually set the X-Forwarded-For header:

*** Just to be clear, this is only a reproduction ChatGPT helped me with. No clue if PUBG’s real setup looked anything like this.
From there, the bypass was straightforward: change the header, reset the counter, keep sending requests.
and turns out, PUBG has been vibecoding this way the whole time.