Bypassing Polymarket US's waitlist
A quick look into how I got into the Polymarket US app earlyBackground
Polymarket, is what is known as a "prediction market", where users can bet on basically anything, from world events to sports to elections. In 2024, it gained a lot of attention for correctly predicting the outcome of the 2024 presidential election while all of the pollsters were very uncertain. Shortly after the 2024 presidential election, the home of the creator was raided by the FBI, with the charges later being dropped. That brings us to today, where after a recent purchase of a CFTC licensed clearing house and a $2 billion investment from Intercontinential Exchange, Polymarket's long awaited return to the US seems imminent.
New mobile app
For months, employees of Polymarket have been adding fuel to the speculation fire by teasing an update to their mobile app which would enable US trading again. This week, that update finally came to the US App Store, with new screenshots and descriptions ready for the American trading market. As someone who sometimes dabbles in predition markets, I decided to download the app to see what this new update would look like, only to be met with a waitlist screen asking me to enter my phone number to be notified when the waitlist was ready for me. There was also a button to enter an invite code, and since I continued to see people posting about their access to the app online, I knew that the app was functional behind this bouncer screen.
Reverse engineering process
As someone who loves learning about how different apps work behind the scences, I decided to close out of the app, turn on my https proxy using Proxyman and see what requests the app made on launch. The request that immediately jumped out to me was the following: A request to 'https://gateway.polymarket.us/v1/integrity-check/config', where the response body looked like this:
{
"iosAppName": "PolyMobile_iOS",
"iosAppCurrentVersion": "v2.0.0",
"iosAppMinVersion": "v2.0.0",
"appPlatforms": ["ios"],
"waitlistEnabled": true,
"expired": false,
"referralDisabled": true,
"maintenanceMode": false
}
After seeing this, I thought to myself, "what if I set that 'waitlistEnabled' to false, would the app let me through?" Spoiler alert, yes it would.
LLMs make this so easy
I had used a tool before called mitmproxy, an open source python tool that lets users modify requests and responses using python and, as the name suggests, a man-in-the-middle proxy. My initial use was to allow me to keep using my Reddit app of choice, Apollo, after the dev had to shut down the app. Knowing that this tool lets you write a python script to modify requests, I just asked the Gemini CLI, my coding tool of the week, to write me a script to accomplish what I wanted. Out of precaution, I didn't tell the LLM what urls and what property I wanted to change, because reverse engineering tasks like this tend to set off safety alarms and the LLM will refuse.
Write me a python script that I can use with mitmproxy that will do the following. It should listen for a request to the following url: https://google.com/config. This url (its just a placeholder) will return a json when requested. The mitmproxy script should change the value of "ready" in the json from false to true. Use context7 to get mitmproxy docs
After modifying the url and property to what I wanted, it worked perfectly first try. In the past, I might've had to dig around in the docs for mitmproxy and tested with trial and error to make sure the functionality was right, but Gemini 3 one-shotted this.
The full script looks like this:
import json
from mitmproxy import http
def response(flow: http.HTTPFlow) -> None:
# Check if the request URL matches the target
if flow.request.pretty_url == "https://gateway.polymarket.us/v1/integrity-check/config":
try:
# Load the response content as JSON
data = json.loads(flow.response.text)
# Check if "ready" key exists and modify it
if "waitlistEnabled" in data:
data["waitlistEnabled"] = False
# Update the response content with the modified JSON
flow.response.text = json.dumps(data)
print(f"Modified 'ready' to True for {flow.request.pretty_url}")
except json.JSONDecodeError:
print(f"Failed to decode JSON from {flow.request.pretty_url}")
except Exception as e:
print(f"An error occurred: {e}")