How I analyze API security headers in 30 seconds
A quick checklist for reading HTTP response headers and spotting security misconfigurations before you even look at the response body.
When I hit an API endpoint for the first time, I don't look at the response body. I look at the headers. They tell you more about the backend's security posture in 30 seconds than the docs ever will.
This is the exact flow I run — usually with a single curl command before I even open the app.
The one-liner that starts everything
$ curl -sI https://api.target.com/v1/me -H "Authorization: Bearer <token>"
HTTP/2 200
server: nginx/1.19.0
x-powered-by: Express
content-type: application/json; charset=utf-8
access-control-allow-origin: *
access-control-allow-credentials: true
set-cookie: session=abc123; Path=/
x-request-id: 7f3a2b1c
content-length: 1842That's a real (sanitized) response I got from a fintech API last year. Let me walk through what I see — and what's wrong.
🚨 Red flag #1: Server version disclosure
server: nginx/1.19.0
x-powered-by: ExpressTwo pieces of information the attacker shouldn't have. Nginx 1.19.0 has known CVEs. X-Powered-By: Expressconfirms it's a Node.js backend — which narrows down the attack surface significantly. I now know to look for prototype pollution, SSRF via request libraries, and common Express misconfigurations.
💡 Fix
Strip version from server header in nginx config: server_tokens off;. Remove X-Powered-By in Express: app.disable('x-powered-by').
🚨 Red flag #2: Wildcard CORS + credentials
access-control-allow-origin: *
access-control-allow-credentials: trueThis combination is a textbook vulnerability. It means: "any website can make authenticated requests to this API, and the browser will include cookies." In practice, browsers block * with credentials — but many APIs reflect the Origin header instead, which is even worse. I test this immediately:
$ curl -sI https://api.target.com/v1/me \
-H "Origin: https://evil.com" \
-H "Authorization: Bearer <token>"
# If response includes:
# access-control-allow-origin: https://evil.com
# → Full CORS bypass. Any site can steal user data.⚠️ Severity: High
Origin reflection with credentials is a P1 in most bug bounty programs. It allows full account takeover via a malicious page.
🚨 Red flag #3: Cookie without security flags
set-cookie: session=abc123; Path=/This cookie is missing every security attribute that matters:
- No
Secure— cookie sent over HTTP too (interceptable on public WiFi) - No
HttpOnly— JavaScript can read it (XSS → session theft) - No
SameSite— cookie sent on cross-origin requests (CSRF possible)
Compare with what it should look like:
set-cookie: session=abc123; Path=/; Secure; HttpOnly; SameSite=Strict; Max-Age=3600🚨 Red flag #4: Missing security headers entirely
What's NOT in that response is just as telling:
| Missing Header | What it means |
|---|---|
Strict-Transport-Security | No HSTS — downgrade attacks possible |
X-Content-Type-Options | MIME sniffing can turn JSON into executable |
Content-Security-Policy | No XSS mitigation at browser level |
X-Frame-Options | Clickjacking possible |
🚨 Red flag #5: No rate limiting indicators
No X-RateLimit-Limit, no X-RateLimit-Remaining, no Retry-After. This usually means there's no rate limiting at all. I confirm with a quick burst:
$ for i in $(seq 1 100); do
curl -so /dev/null -w "%{http_code}" \
https://api.target.com/v1/users/$i \
-H "Authorization: Bearer <token>"
done | sort | uniq -c
# Output:
100 200
# 100 requests, all 200. No rate limiting. Enumeration is trivial.The full checklist (my mental model)
┌─ HEADERS SECURITY CHECKLIST ─────────────────────┐
│ │
│ [1] Server/X-Powered-By → version leak? │
│ [2] CORS → origin reflected? credentials? │
│ [3] Set-Cookie → Secure? HttpOnly? SameSite? │
│ [4] HSTS → present? max-age > 1 year? │
│ [5] CSP → present? restrictive? │
│ [6] X-Content-Type-Options → nosniff? │
│ [7] Rate limit headers → present? │
│ [8] Cache-Control → no sensitive data cached? │
│ │
└──────────────────────────────────────────────────┘Why this matters for automation engineers
If you're building automation against an API, these headers tell you how much resistance you'll face. No rate limiting? Your scraper won't get blocked. Weak CORS? You might be able to piggyback on existing sessions. Leaky server headers? You know exactly what stack you're dealing with.
And if you're on the defensive side — these are the first things an attacker checks. Fix them before they find them.
Related posts
- Security ResearchMay 18, 20269 min read
Common auth mistakes I find when reverse-engineering APIs
After years of poking at APIs that weren't meant to be poked at, these are the auth patterns that break most often — and why.
- Security ResearchMay 19, 20266 min read
How I got free cinema credit by ordering -2 popcorns
A missing input validation on M-Tix Cinema XXI's food ordering API let me increase my account balance by submitting negative quantities. No tools needed — just a browser.
- API Reverse EngineeringMay 18, 20268 min read
What your JWT tokens reveal about your backend
JWTs are meant to be opaque to users. They're not. Here's what I learn about your architecture just by decoding one.