DEV Community

Bob
Bob

Posted on • Originally published at capbypass.pro

Bypass AWS WAF challenges in Python

AWS WAF drops a JavaScript challenge in front of a page before any real response comes back, and a plain Python request just gets the challenge HTML instead of your data. This post detects that challenge, solves it through CapBypass, and replays the returned cookie on the request - about 30 lines of Python.


what aws waf blocks

AWS WAF's challenge sits between your client and the origin. On a protected page you get an interstitial that runs challenge.js (a proof-of-work token generator) and only sets the real aws-waf-token cookie once the JavaScript finishes. A scraper that does not run that JS never gets the cookie, so every request loops back to the challenge.

The tell is in the response: a small HTML page that loads a script from *.token.awswaf.com, often with an HTTP 405 and a window.gokuProps object holding key, iv, and context.


detecting the challenge

Check the body for the AWS WAF markers before you trust a response:

def is_waf_challenge(resp):
    body = resp.text
    return (
        "token.awswaf.com" in body
        or "gokuProps" in body
        or 'awswaf' in resp.headers.get("server", "").lower()
    )
Enter fullscreen mode Exit fullscreen mode

If is_waf_challenge is true, the page is gated and you need a solved cookie before retrying.


solving with capbypass

Send the target URL to CapBypass with the AntiAwsWafTaskProxyLess task. With auto-detection you only pass websiteURL - the solver visits the page, finds gokuProps and the challenge.js URL, and runs the challenge for you.

curl -s https://api.capbypass.pro/createTask \
  -H 'Content-Type: application/json' \
  -d '{
    "clientKey": "YOUR_API_KEY",
    "task": {
      "type": "AntiAwsWafTaskProxyLess",
      "websiteURL": "https://example.com/protected-page"
    }
  }'
Enter fullscreen mode Exit fullscreen mode
{ "errorId": 0, "taskId": "5f9b...-uuid" }
Enter fullscreen mode Exit fullscreen mode

Poll getTaskResult until status is ready:

{
  "status": "ready",
  "solution": {
    "cookie": "aws-waf-token=xxxxxxxx...",
    "token": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx:...",
    "userAgent": "Mozilla/5.0 ...",
    "secChUa": "\"Chromium\";v=\"...\""
  }
}
Enter fullscreen mode Exit fullscreen mode

The same flow in Python with the Python SDK:

import os
from capbypass import CapBypass

client = CapBypass(api_key=os.environ["CAPBYPASS_API_KEY"])

result = client.solve({
    "type": "AntiAwsWafTaskProxyLess",
    "websiteURL": "https://example.com/protected-page",
})

solution = result["solution"]
cookie = solution["cookie"]          # "aws-waf-token=..."
user_agent = solution["userAgent"]   # match this on your request
Enter fullscreen mode Exit fullscreen mode

For the full parameter list (manual awsKey / awsIv / awsContext situations) see the AWS WAF docs and the API reference.

AWS WAF solve flow: a JS challenge blocks the request, AntiAwsWafTaskProxyLess solves it, you get an aws-waf-token cookie, and you replay the request.


replaying the cookies

AWS WAF binds the token to the browser identity that solved it, so set the returned cookie and reuse the same userAgent on your retry. Match them or the origin re-challenges you.

import requests

session = requests.Session()
name, value = cookie.split("=", 1)
session.cookies.set(name, value, domain="example.com")
session.headers["User-Agent"] = user_agent

resp = session.get("https://example.com/protected-page")
# resp is now the real page, not the challenge
Enter fullscreen mode Exit fullscreen mode

Keep the session alive and the cookie rides along on every subsequent request until it expires.


Bonus: +5% credits on every top-up

New to CapBypass? Apply code WELCOME_2026 at checkout for an extra 5% in credits on every top-up, with no minimum and no expiry. Redeem it on the top-up page and put it toward your first AntiAwsWafTaskProxyLess solves.


things that go wrong

  • User-Agent mismatch. The token is tied to the UA used during the solve. If your request UA differs from solution.userAgent, AWS WAF rejects the cookie. Always copy it over (and secChUa if you send client hints).
  • Token expired. aws-waf-token is short-lived. Solve, replay, and finish the request promptly instead of queueing the cookie for later.
  • Wrong domain on the cookie. Set the cookie on the exact host you are hitting, not a parent domain.
  • Visual CAPTCHA instead of JS challenge. Some WAF configs escalate to an image CAPTCHA; the solution then carries a captchaVoucher JWT rather than a plain cookie. Handle both keys.

faq

Do I need a proxy for AWS WAF?
Not with AntiAwsWafTaskProxyLess - it runs through the CapBypass pool. For IP-sensitive targets use AntiAwsWafTask and pass your own proxy as host:port:user:pass.

Why does the page still challenge me after I set the cookie?
Almost always a User-Agent mismatch. The token is bound to the UA from the solve, so send solution.userAgent on the same request that carries the cookie.

How long is the aws-waf-token valid?
It is short-lived (minutes). Treat it as single-session: solve, replay immediately, and re-solve when it expires rather than caching it.

What if there is no gokuProps on the page?
Pass just the websiteURL and let auto-detection find the challenge.js script. If the site hides it, supply awsChallengeJS (and awsKey / awsIv / awsContext) manually per the docs.


Originally published on capbypass.pro. CapBypass is an AI-powered captcha-solving API for reCAPTCHA, hCaptcha, Cloudflare Turnstile and AWS WAF.

Top comments (0)