Cloudflare WAF Bypass Discovery 🎯
The Breakthrough Finding
We discovered that Cloudflare WAF was NOT blocking the Contabo IP from the WordPress REST API. This was a critical misconception that had blocked deployment for days.
What Actually Happened
We assumed Cloudflare's WAF was blocking 172.17.0.1 (our Contabo Docker host) from reaching ummah.falahos.my/wp-json/. This assumption was wrong.
Evidence:
$ curl -s -w "HTTP %{http_code}" "https://ummah.falahos.my/wp-json/wp/v2/users"
HTTP 200
$ curl -s -w "HTTP %{http_code}" "https://ummah.falahos.my/wp-json/wp/v2/plugins"
HTTP 401
The WP REST API was fully reachable — it just returned:
- HTTP 200 for public endpoints (users, index, etc.)
- HTTP 401 for protected endpoints (plugins, etc.) — not a WAF block!
Why We Thought It Was Blocked
Earlier testing used /wp-json/hermes/v1/content/generate which returned HTTP 404 (plugin not installed yet, not blocked). And the assumption that cPanel shared hosting behind Cloudflare would block non-browser traffic was natural but incorrect.
The Real Blocker
The actual blocker was authentication, not Cloudflare:
WP REST API needs → Application Password (HTTP Basic Auth)
→ OR Cookie + Nonce (browser-based auth)
Cloudflare WAF was never the issue — we just needed a WordPress Application Password.
Solution: Application Passwords
WordPress Application Passwords provide app-layer authentication via HTTP Basic Auth:
curl -u "username:application_password" \
"https://ummah.falahos.my/wp-json/wp/v2/plugins"
This bypasses any WAF because the auth happens at the application layer inside WordPress, not at the network level.
How to Create
Via REST API (if already logged in):
# 1. Log in with cookie auth
curl -c cookies.txt \
-d "log=wmj&pwd=PASSWORD&wp-submit=Log+In" \
"https://ummah.falahos.my/wp-login.php"
# 2. Extract nonce from admin page
NONCE=$(curl -b cookies.txt \
"https://ummah.falahos.my/wp-admin/profile.php" \
| grep -oP '"nonce":"[^"]*"' | head -1 | cut -d'"' -f4)
# 3. Create Application Password
curl -b cookies.txt \
-H "X-WP-Nonce: $NONCE" \
-H "Content-Type: application/json" \
-d '{"name":"my-agent"}' \
"https://ummah.falahos.my/wp-json/wp/v2/users/me/application-passwords"
Via Admin UI:
- Log in to
https://ummah.falahos.my/wp-admin - Go to Users → Profile
- Scroll to "Application Passwords" section
- Enter a name and click "Add New"
- Copy the generated password
Key Takeaway
Always verify assumptions about network-level blocking before engineering complex workarounds. Test with curl -w "HTTP %{http_code}" first to distinguish between:
- HTTP 403/503 → WAF or server block
- HTTP 401 → Authentication needed (WordPress is responding!)
- HTTP 404 → Endpoint not found (plugin not installed)
Related
- WordPress Application Passwords plugin is already installed on ummah.falahos.my
- Gitea Actions CI/CD uses
WP_APP_PASSWORDsecret for auto-deployment - The CF API token (
cfut_...) has DNS:Edit + Zone:Read scopes but NOT WAF management