July 23, 2026
Bypassing reCAPTCHA Due to Missing Server-Side Validation
اللَهُمَّ صلِّ وسَلِم وبَارِك على سيدنا محمد (ﷺ)

By 0X0DOoOM
2 min read
اللَهُمَّ صلِّ وسَلِم وبَارِك على سيدنا محمد (ﷺ)
Hello Hackers, that's 0x0DoooM again
When reCAPTCHA Exists but Isn't Enforced
Most developers think that once reCAPTCHA is integrated, automated abuse is no longer a concern. Unfortunately, that's not always true.
During a security assessment, I found that the application verified a valid reCAPTCHA token only once, but never prevented missing token. As a result, a single solved CAPTCHA was enough to automate unlimited requests.
At that point, reCAPTCHA became worth it to investigate a little bit.
Understanding How reCAPTCHA Should Work
The normal flow is straightforward:
- The user solves the CAPTCHA challenge.
- Google generates a reCAPTCHA token.
- The application sends that token to Google's verification endpoint.
- Google validates the token and returns whether it is valid.
- The application should treat that token as single-use and reject any future requests using the same token or any request miss token.
Google's documentation also states that tokens are intended to be short-lived and verified only once.
If the server skips this final validation logic, the protection can be bypassed entirely.
The Issue
While testing the registration endpoint, I noticed that the server accepted the same request without reCAPTCHA token.
Instead of rejecting previously verified tokens, every request containing without token was processed successfully.
This meant I only needed to solve the CAPTCHA once.
After that, I could continuously replay the exact same request.
POST /signup
g-recaptcha-response=<token>
email=user1@example.com
POST /signup
g-recaptcha-response=<same_token> //Removed
email=user2@example.com
POST /signup
g-recaptcha-response=<same_token> //Removed
email=user3@example.comPOST /signup
g-recaptcha-response=<token>
email=user1@example.com
POST /signup
g-recaptcha-response=<same_token> //Removed
email=user2@example.com
POST /signup
g-recaptcha-response=<same_token> //Removed
email=user3@example.comThe token never expired from the application's perspective, as we can see the normal behavior, if we try to use the same captcha again,
Why This Matters
Many applications rely on reCAPTCHA as their primary defense against automation.
If replayed tokens remain valid, attackers no longer need to solve CAPTCHAs repeatedly.
In my case, it allowed continuous account registration using the same CAPTCHA solution and was step to proof that we can bypass rate limit easily and for example go through Brute Force attack, etc.. .
Proof of Concept
The attack was surprisingly simple.
- Solve the CAPTCHA normally.
- Intercept the request in Burp Suite.
- Send the request to Repeater.
- Remove Captcha parameter then Replay the request.
Every request succeeded even without reCAPTCHA token was reused.
The server never detected that the token had already been removed as follows:
Why It Happens
This issue is usually caused by trusting Google's response without implementing proper server-side validation.
Developers often verify that a token is valid but forget an important detail:
A valid token does not mean it should remain valid forever.
Once a token has been accepted, the application should never allow it to be used again.
Without replay protection, reCAPTCHA loses much of its effectiveness.
TRiaged !
The deeper you dive into the details, the clearer the bigger picture becomes.