File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change @@ -67,7 +67,7 @@ PAT instead), and Turnstile is only used by the planned Jira integration.
6767
6868** Verify configuration:** Run ` pnpm validate:deploy ` locally to check that all required
6969Cloudflare Worker secrets are set. In CI, the deploy workflow runs
70- ` pnpm validate:deploy --ci ` automatically before building.
70+ ` pnpm validate:deploy ` automatically before building.
7171
7272### Optional (both deployment paths)
7373
@@ -230,7 +230,7 @@ Configure these rules in the Cloudflare dashboard under **Security → WAF**.
230230** Where:** Security → WAF → Custom Rules
231231** Expression:**
232232```
233- (http.request.uri.path starts_with "/api/") and
233+ (starts_with( http.request.uri.path, "/api/") ) and
234234not (any(http.request.headers["origin"][*] in {"https://YOUR-DOMAIN"})) and
235235not (http.request.uri.path eq "/api/csp-report") and
236236not (http.request.uri.path eq "/api/error-reporting")
@@ -251,7 +251,7 @@ not (http.request.uri.path eq "/api/error-reporting")
251251** Where:** Security → WAF → Rate Limiting Rules
252252** Matching expression:**
253253```
254- (http.request.uri.path starts_with "/api/") and
254+ (starts_with( http.request.uri.path, "/api/") ) and
255255(http.request.method ne "OPTIONS")
256256```
257257** Rate:** 60 requests per 10 seconds per IP
Original file line number Diff line number Diff line change 88# Rules validated:
99# 1. Path Allowlist — blocks all paths except known SPA routes, /assets/*, /api/*
1010# 2. Scanner User-Agents — challenges empty/malicious User-Agent strings
11+ # 3. Origin Gate — blocks /api/* requests without valid Origin header
1112# Rate limit rule exists but is not tested here (triggers a 10-minute IP block).
1213
1314set -euo pipefail
@@ -58,9 +59,12 @@ TESTS=(
5859 " 200|GET /privacy|${BASE} /privacy"
5960 " 307|GET /index.html (html_handling redirect)|${BASE} /index.html"
6061 " 200|GET /assets/nonexistent.js|${BASE} /assets/nonexistent.js"
61- " 200|GET /api/health|${BASE} /api/health"
62- " 400|POST /api/oauth/token (no body)|-X|POST|${BASE} /api/oauth/token"
63- " 404|GET /api/nonexistent|${BASE} /api/nonexistent"
62+ " 200|GET /api/health (with Origin)|-H|Origin: ${BASE} |${BASE} /api/health"
63+ " 400|POST /api/oauth/token (no body)|-X|POST|-H|Origin: ${BASE} |${BASE} /api/oauth/token"
64+ " 404|GET /api/nonexistent|-H|Origin: ${BASE} |${BASE} /api/nonexistent"
65+ # Rule 3: Origin gate — API requests without valid Origin are blocked at WAF
66+ " 403|GET /api/health (no Origin)|${BASE} /api/health"
67+ " 403|POST /api/oauth/token (wrong Origin)|-X|POST|-H|Origin: https://evil.example.com|${BASE} /api/oauth/token"
6468 # Rule 1: Path Allowlist — blocked paths
6569 " 403|GET /wp-admin|${BASE} /wp-admin"
6670 " 403|GET /wp-login.php|${BASE} /wp-login.php"
You can’t perform that action at this time.
0 commit comments