Configure Cross-Origin Resource Sharing correctly to avoid security issues and debugging pain.
Scanned 9/6/2026
Install to Claude Code
npx -y skills add clawic/skills --skill cors --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Cors?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/clawic-cors)More formats (shields.io, HTML) on the badges page.
---
name: CORS
slug: cors
version: 1.0.0
description: Configure Cross-Origin Resource Sharing correctly to avoid security issues and debugging pain.
homepage: https://clawic.com/skills/cors
metadata:
clawdbot:
emoji: 🔀
os:
- linux
- darwin
- win32
displayName: CORS
---
## Preflight Triggers
- Any header except: Accept, Accept-Language, Content-Language, Content-Type (with restrictions)
- Content-Type other than: application/x-www-form-urlencoded, multipart/form-data, text/plain
- Methods: PUT, DELETE, PATCH, or any custom method
- ReadableStream in request body
- Event listeners on XMLHttpRequest.upload
- One trigger = preflight; simple requests skip OPTIONS entirely
## Credentials Mode
- `Access-Control-Allow-Origin: *` incompatible with credentials—must specify exact origin
- `Access-Control-Allow-Credentials: true` required for cookies/auth headers
- Fetch: `credentials: 'include'`; XHR: `withCredentials = true`
- Without credentials mode, cookies not sent even to same origin for cross-origin requests
## Wildcard Limitations
- `*` doesn't match subdomains—`*.example.com` is invalid, not a pattern
- Can't use `*` with credentials—specify origin dynamically from request
- `Access-Control-Allow-Headers: *` works in most browsers but not all—list explicitly for compatibility
- `Access-Control-Expose-Headers: *` same issue—list headers you need to expose
## Origin Validation
- Check Origin header against allowlist—don't reflect blindly (security risk)
- Regex matching pitfall: `example.com` matches `evilexample.com`—anchor the pattern
- `null` origin: sandboxed iframes, file:// URLs—usually reject, never allow as trusted
- Missing Origin header: same-origin or non-browser client—handle explicitly
## Vary Header (Critical)
- Always include `Vary: Origin` when response depends on origin—even if you allow only one
- Without Vary: CDN/proxy caches response for one origin, serves to others—breaks CORS
- Add `Vary: Access-Control-Request-Headers, Access-Control-Request-Method` for preflight caching correctness
## Exposed Headers
- By default, JS can only read: Cache-Control, Content-Language, Content-Type, Expires, Last-Modified, Pragma
- Custom headers invisible to JS unless listed in `Access-Control-Expose-Headers`
- `X-Request-ID`, `X-RateLimit-*`, etc. need explicit exposure—common oversight
## Preflight Caching
- `Access-Control-Max-Age: 86400` caches preflight for 24h—reduces OPTIONS traffic significantly
- Chrome caps at 2 hours; Firefox at 24 hours—values above are silently reduced
- Cached per origin + URL + request characteristics—not globally
- Set to 0 or omit during development—caching hides config changes
## Debugging
- CORS error in browser = request reached server and came back—check server logs
- Preflight failure: server must return 2xx with CORS headers on OPTIONS—404/500 = failure
- Opaque response in fetch: `mode: 'no-cors'` succeeds but response is empty—usually not what you want
- Network tab shows CORS errors; Console shows which header is missing
## Common Server Mistakes
- Only setting CORS headers on main handler, not OPTIONS—preflight fails
- Setting headers after error response—CORS headers missing on 4xx/5xx breaks error handling
- Proxy stripping headers—verify headers reach client, not just that server sets them
- `Access-Control-Allow-Origin: "*", "https://example.com"`—must be single value, not list
## Security
- Don't reflect Origin header blindly—validate against allowlist first
- Private Network Access: Chrome requires `Access-Control-Allow-Private-Network: true` for localhost access from public web
- CORS doesn't prevent request from being sent—just blocks response reading; server still processes it
- Sensitive endpoints: don't rely on CORS alone; use authentication + CSRF tokens
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!