CORS misconfiguration hunting on EU bug bounty targets: one real finding out of five
One CORS HIGH out of five EU targets: RIPE NCC's wildcard ACAO with write methods. What it looked like, how SecurityClaw found it, and how to spot it.
Affiliate Disclosure: This site contains affiliate links. We earn a commission when you purchase through our links at no additional cost to you.
Run a CORS scanner against five EU bug bounty targets today and you will probably find noise plus one real thing β if you are lucky. That is roughly what happened when Peng ran SecurityClawβs apigw-cors-tester against vinted.com, wolt.com, odoo.com, ripe.net, and visma.com.
Four were clean. One had a genuine HIGH-severity CORS wildcard on the main domain with full method exposure. What follows is what the scanner found, what the actual evidence looked like, and the false positive patterns that will eat most of your time in this class of bug.
What the scanner does
apigw-cors-tester sends six distinct probes to each target:
- OPTIONS preflight with attacker origin β checks if the server reflects a foreign origin in
Access-Control-Allow-Origin - GET with attacker origin β the real test; if ACAO is wildcard or reflects the origin, cross-origin reads are possible
- GET with
Origin: nullβ sandboxed iframe bypass (browsers send null fromdata:URIs and sandboxed iframes) - Suffix confusion β tests
Origin: https://attacker-target.comto catch naiveendsWith()validators - Gateway fingerprinting β identifies CDN/gateway from response headers (CloudFront, Cloudflare, nginx, etc.)
- PoC snippet generation β writes a minimal JavaScript proof-of-concept if a wildcard or reflection is found
Severity classification is:
| Condition | Severity |
|---|---|
ACAO: * + ACAC: true | CRITICAL β potential credential theft |
ACAO: * alone | HIGH β unauthenticated cross-origin read |
| Arbitrary origin reflected | HIGH β targeted cross-origin read |
null origin accepted | MEDIUM β sandboxed iframe bypass |
| No CORS issues | LOW β no finding |
The CRITICAL scenario (ACAO: * combined with Access-Control-Allow-Credentials: true) is worth understanding even if it is rare. The Fetch Standard means browsers will not include cookies when ACAO: * is set β credentialed cross-origin requests require an explicit origin in ACAO, not a wildcard β but some older CDN configs and custom middleware can accidentally set both headers together. Check for it even when it seems impossible.
The results
| Target | CORS | Result |
|---|---|---|
| vinted.com | Clean | LOW |
| wolt.com | Clean | LOW |
| odoo.com | Clean | LOW |
| ripe.net | ACAO: * | HIGH |
| visma.com | Clean | LOW |
Four that came up clean
vinted.com returns no Access-Control-Allow-Origin header at all on non-CORS requests. OPTIONS returns 405 β there are no CORS headers. Correctly locked down.
wolt.com is the standout in this cohort on header hygiene. No CORS issues, and a CSP with 46 SHA-256 script hashes, a frame-ancestors 'self' directive, and a Datadog EU CSP reporting endpoint (browser-intake-datadoghq.eu). That reporting endpoint means their AppSec team sees violations in real time. If you want an example of a consumer app that has actually invested in headers, Wolt is it.
odoo.com returns no CORS headers on the main domain. OPTIONS returns 200 with nothing β nginx handles the preflight at the server level but does not reflect origins. No finding.
visma.com has no CORS issues but the worst overall header posture in the cohort. No CSP, no X-Frame-Options, no COOP, no CORP, no Referrer-Policy. Everything absent. No CORS finding, but informational if you are building a report on the full attack surface.
The one that mattered: ripe.net
The scanner returned a genuine HIGH on the main domain.
CORS wildcard: YES β Access-Control-Allow-Origin: *
Origin reflected: No
Credentialed wildcard: No (ACAC absent)
Gateway: nginx
Allowed methods: DELETE, GET, OPTIONS, PATCH, POST, PUT
Raw evidence β OPTIONS preflight to www.ripe.net after redirect:
HTTP/2 200
server: nginx
access-control-allow-origin: *
access-control-allow-headers: accept, authorization, content-type, user-agent, x-csrftoken, x-requested-with
access-control-allow-methods: DELETE, GET, OPTIONS, PATCH, POST, PUT
access-control-max-age: 86400
x-frame-options: DENY
Raw evidence β GET with Origin header:
HTTP/2 200
access-control-allow-origin: *
x-frame-options: DENY
This was not OPTIONS-only. Both the preflight and the actual GET returned the wildcard. Keep that in mind when you hit the false positive section below.
The Authorization header is explicitly included in Access-Control-Allow-Headers. If any endpoint on www.ripe.net uses token-based authentication rather than cookies, those endpoints are attackable cross-origin β any JavaScript payload on any third-party page can read the response.
The method exposure matters too. RIPEβs wildcard response includes DELETE, GET, OPTIONS, PATCH, POST, PUT, which signals that the domain is intended to accept cross-origin write operations. For public-facing endpoints, that is probably fine β and RIPEβs actual REST database API at rest.db.ripe.net has no wildcard, which suggests they understand the distinction. But the main domain carrying wildcard CORS on top of write methods is worth documenting.
RIPE NCCβs WHOIS data is publicly available, so cross-origin reads on public responses are lower impact than they would be for, say, a banking portal. The submission severity is HIGH, possibly borderline MEDIUM depending on whether any authenticated portal endpoints exist at www.ripe.net. Manual follow-up to enumerate authenticated surfaces would strengthen the report.
The scan was run 2026-05-10T00:09Z from a clean IP against all five targets. All five programs permit automated tooling explicitly in their Intigriti program policies.
How to spot false positives
CORS scanners are noisy. Three patterns come up constantly:
1. Intentional public data APIs
ACAO: * is correct for genuinely public data endpoints that intentionally allow cross-origin reads. A weather API that returns public data with a wildcard is not a finding. The distinction is whether the endpoint has authenticated or user-specific data. Public read-only APIs with ACAO: * are usually architecture, not misconfiguration.
Check the endpoint type before reporting. If it returns the same data for every user and there is no authentication surface, it is probably intentional.
2. Static asset CDNs
Font CDNs, image CDNs, and JS CDN endpoints return ACAO: * by design β they need to be loadable from any domain. The scanner does not distinguish CDN asset URLs from application endpoints.
Content-Type is your quick filter. Content-Type: font/woff2 or image/png with ACAO: * is a CDN. Content-Type: application/json with ACAO: * on an endpoint that handles auth is a finding.
3. OPTIONS wildcard with no ACAO on GET
Some servers return ACAO: * on OPTIONS preflights but omit the header on actual GET responses. Browsers check ACAO on the actual response, not just the preflight β if the GET response has no ACAO, the browser blocks the cross-origin read even though the preflight succeeded.
The scanner may flag this as HIGH because the preflight returned a wildcard. It is not exploitable. Always verify manually by sending a GET with an Origin header and checking whether the response includes ACAO: *. The RIPE NCC finding above cleared this check β both the preflight and the GET returned the wildcard.
Header comparison across the five targets
| Target | CORS | CSP | X-Frame-Options | COOP | Referrer-Policy |
|---|---|---|---|---|---|
| vinted.com | β | β | β | β | β |
| wolt.com | β | β Strong | β SAMEORIGIN | β | β |
| odoo.com | β | β | β | β | β |
| ripe.net | β οΈ HIGH | β | β DENY | β same-origin | β |
| visma.com | β | β | β | β | β |
RIPE has the right instincts on traditional isolation headers (X-Frame-Options, COOP, Referrer-Policy), but the CORS wildcard cuts against the isolation those headers are meant to provide. The CDN vendor also correlates loosely with security posture: the CloudFront-hosted target (Wolt) had better header hygiene than the Cloudflare-hosted ones. Cloudflareβs default config is less opinionated about security headers β Cloudflare customers add them manually, and many do not.
Remediation
For application endpoints that need cross-origin access, replace the wildcard with an explicit allowlist:
# nginx β explicit origin allowlist
set $cors_origin "";
if ($http_origin ~* "^https://(app\.yoursite\.com|api\.yoursite\.com)$") {
set $cors_origin $http_origin;
}
add_header Access-Control-Allow-Origin $cors_origin always;
add_header Vary Origin always;
Add Vary: Origin too. Without it, CDN edge caches may serve a CORS response cached for one origin to a different origin.
For public APIs where cross-origin reads are intentional, ACAO: * is correct. Make sure no authenticated or write endpoints share the same domain.
A full isolation header baseline for EU targets:
add_header X-Frame-Options "DENY" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Cross-Origin-Opener-Policy "same-origin" always;
add_header Cross-Origin-Resource-Policy "same-origin" always;
Replace "DENY" with "SAMEORIGIN" or a CSP frame-ancestors directive if your application embeds iframes.
What the scanner does not cover
The scan above hit the main domains only. Three gaps worth knowing about:
The scanner tests unauthenticated OPTIONS/GET only. CORS misconfigs on authenticated endpoints are higher impact by definition, but they require an active session token. SecurityClawβs authenticated campaign tooling handles that separately.
Subdomain scope is another gap. CORS misconfigs often live on obscure subdomains (api2., legacy., internal-api.). The scanner only tests the URL you give it. Pairing it with CT-log enumeration would increase coverage significantly.
Origin reflection variants are also out of scope. The scanner sends one attacker origin. Production testing should also try suffix injection (Origin: https://yoursite.com.attacker.com), backslash bypass on broken parsers, capitalisation variants, and null origin.
If the main domain came up clean, those are the next places to check.
Frequently Asked Questions
What is a CORS misconfiguration in bug bounty?
A CORS (Cross-Origin Resource Sharing) misconfiguration lets a malicious website read data from a target API that should be restricted to same-origin requests. The most common finding is an overly permissive Access-Control-Allow-Origin header β either a wildcard (*) or a header that reflects any origin the attacker sends. On bug bounty platforms like Intigriti, CORS wildcards on API endpoints typically qualify as HIGH severity.
How do you detect CORS misconfigurations automatically?
SecurityClawβs apigw-cors-tester sends six probes per target: an OPTIONS preflight with an attacker origin, a GET with attacker origin, a GET with Origin: null (sandboxed iframe bypass), a suffix-confusion test, a gateway fingerprint, and a PoC snippet if a finding is confirmed. Manual verification is still required β automated tools generate false positives on CDN-cached responses and gateway defaults that donβt represent actual server behavior.
What is the difference between ACAO wildcard and origin reflection?
A wildcard (Access-Control-Allow-Origin: *) allows any origin to read the response but blocks credentialed requests by spec. Origin reflection mirrors whatever the attacker sends in the Origin header β this is a direct HIGH finding because it allows targeted cross-origin reads, and unlike wildcards it can be combined with Access-Control-Allow-Credentials: true for credential theft.
How do you remediate a CORS misconfiguration?
Replace the wildcard or reflection logic with an explicit origin allowlist. In nginx: check $http_origin against a regex of approved origins and only set Access-Control-Allow-Origin when the origin matches. Always add Vary: Origin to prevent CDN edge caches from serving a CORS response cached for one origin to a different origin. For public APIs where cross-origin reads are intentional, a wildcard is correct β ensure no authenticated endpoints share the same domain.
Testing CORS manually requires a proxy that can intercept and modify Origin headers mid-flight. Burp Suite Professional handles this out of the box: the Proxy tab catches the preflight, Repeater lets you craft variant Origin values without rewriting your curl commands each time. If you want to practice the detection methodology in a controlled environment before touching live programs, Hack The Box has dedicated web security labs covering CORS and cross-origin data theft scenarios.
If you are working through false positive patterns in other vulnerability classes, open redirect false positives on EU bug bounty targets follows the same filter-first methodology. Once you have a confirmed CORS finding, the bug bounty submission guide for Intigriti, HackerOne, Bugcrowd, and YesWeHack covers exactly what the form expects and how to frame CORS severity for each platform. The compound chain β CORS misconfiguration plus OAuth on the same endpoint β is documented in the CORS + OAuth compound account takeover walkthrough.