Skip to content

CORS Testing — How to Verify Cross-Origin Configuration with Curl, Postman, and Browsers

DodaTech Updated 2026-06-28 4 min read

In this tutorial, you will learn about CORS Testing. We cover key concepts, practical examples, and best practices to help you master this topic.

CORS testing requires validating headers at multiple levels: with curl for server-side configuration, with Postman for manual interactive testing, and in the browser for true client-side behavior verification.

What You'll Learn

  • Testing CORS with curl commands
  • Using Postman for CORS validation
  • Automating CORS tests in CI/CD

Why It Matters

CORS misconfigurations can silently block production traffic or expose security vulnerabilities. Automated CORS testing in CI/CD prevents deployment of broken configurations. DodaTech's CI pipeline runs CORS tests against every API deployment.

flowchart LR
    A["CORS Testing Strategy"] --> B["curl: Basic header check"]
    A --> C["Postman: Manual testing"]
    A --> D["Browser: Real behavior"]
    A --> E["Automated: CI/CD tests"]
    B --> F["Verify ACAO, ACAC presence"]
    C --> G["Test multiple origins"]
    D --> H["Verify preflight + actual"]
    E --> I["Regression tests per deploy"]

Code Examples

# Complete curl CORS test suite
# 1. Test simple GET request
echo "=== Test 1: Simple GET ==="
curl -s -I -H "Origin: https://app.example.com" \
  https://api.example.com/data | grep -i "access-control"

# 2. Test preflight
echo "=== Test 2: Preflight OPTIONS ==="
curl -s -X OPTIONS -I \
  -H "Origin: https://app.example.com" \
  -H "Access-Control-Request-Method: POST" \
  -H "Access-Control-Request-Headers: Content-Type" \
  https://api.example.com/data | grep -i "access-control"

# 3. Test blocked origin
echo "=== Test 3: Blocked Origin ==="
curl -s -I -H "Origin: https://evil.com" \
  https://api.example.com/data | grep -i "access-control"

# 4. Test with credentials
echo "=== Test 4: With Credentials ==="
curl -s -I -H "Origin: https://app.example.com" \
  -H "Cookie: session=abc" \
  https://api.example.com/profile | grep -i "access-control"
// Automated CORS test with Node.js
const http = require('http');

function testCors(origin, url, method = 'GET') {
  return new Promise((resolve, reject) => {
    const options = {
      headers: { 'Origin': origin },
      method: method === 'OPTIONS' ? 'OPTIONS' : method
    };

    const req = http.request(url, options, (res) => {
      const headers = res.headers;
      const result = {
        origin,
        url,
        method: options.method,
        'access-control-allow-origin': headers['access-control-allow-origin'],
        'access-control-allow-methods': headers['access-control-allow-methods'],
        'access-control-allow-credentials': headers['access-control-allow-credentials'],
        status: res.statusCode
      };
      resolve(result);
    });
    req.end();
  });
}

// Test multiple scenarios
async function runCorsTests() {
  const tests = [
    { origin: 'https://app.example.com', url: 'http://localhost:3000/api/data' },
    { origin: 'https://evil.com', url: 'http://localhost:3000/api/data' },
    { origin: 'https://app.example.com', url: 'http://localhost:3000/api/data', method: 'OPTIONS' }
  ];

  for (const test of tests) {
    const result = await testCors(test.origin, test.url, test.method);
    console.log(result);
  }
}
# Automated CORS tests with pytest
import requests

class TestCORS:
    BASE_URL = "https://api.example.com"
    ALLOWED_ORIGIN = "https://app.example.com"
    BLOCKED_ORIGIN = "https://evil.com"

    def test_allowed_origin_has_acao(self):
        response = requests.get(
            f"{self.BASE_URL}/data",
            headers={"Origin": self.ALLOWED_ORIGIN}
        )
        assert response.headers.get("Access-Control-Allow-Origin") == "*"

    def test_preflight_allows_post(self):
        response = requests.options(
            f"{self.BASE_URL}/data",
            headers={
                "Origin": self.ALLOWED_ORIGIN,
                "Access-Control-Request-Method": "POST"
            }
        )
        methods = response.headers.get("Access-Control-Allow-Methods", "")
        assert "POST" in methods

    def test_blocked_origin_should_have_no_acao(self):
        """For dynamic origin APIs, blocked origins should have no ACAO"""
        response = requests.get(
            f"{self.BASE_URL}/secure-data",
            headers={"Origin": self.BLOCKED_ORIGIN}
        )
        acao = response.headers.get("Access-Control-Allow-Origin")
        assert acao is None or acao != self.BLOCKED_ORIGIN

Common Mistakes

1. Testing Only with Curl

Curl does not enforce CORS. Always verify in a real browser.

2. Not Testing Blocked Origins

Positive tests are not enough. Verify that unauthorized origins are actually blocked.

3. Ignoring Preflight Testing

Preflight requests may have different behavior than actual requests. Test both.

4. Not Testing with Credentials

CORS behavior with credentials differs significantly. Test both credentialed and anonymous requests.

5. Testing Only Against Production

Test CORS in staging with the same configuration as production to catch issues before deployment.

Practice Questions

  1. What curl flag shows response headers?
  2. How do you simulate a preflight request with curl?
  3. What is the difference between testing CORS with curl vs a browser?
  4. How do you automate CORS tests in CI/CD?
  5. What should you test beyond the happy path?

Answers:

  1. -I (or --head) shows response headers only.
  2. Use -X OPTIONS with Access-Control-Request-Method and Access-Control-Request-Headers headers.
  3. Curl shows what the server sends; the browser actually enforces CORS rules.
  4. Use pytest or Jest to send requests with custom Origin headers and assert CORS response headers.
  5. Test blocked origins, missing headers, credential conflicts, and preflight failures.

Challenge: Build a comprehensive CORS testing framework that runs in CI/CD. Include tests for allowed origins, blocked origins, preflight requests, credentialed requests, wildcard configurations, and header exposure. Generate a CORS Compliance report.

FAQ

Can I use browser developer tools to test CORS?

Yes. The Network tab in Chrome DevTools shows every request and response header. Filter by 'cors' or examine individual requests for CORS headers.

What is the best Postman configuration for CORS testing?

In Postman, set a custom Origin header in the Headers tab. Postman does not enforce CORS, so it only shows server response headers without browser blocking.

How do I test CORS for WebSocket connections?

WebSocket CORS is handled differently. Use the WebSocket handshake request headers to verify Origin is present and the server responds with appropriate headers.

Should I test CORS in every CI/CD pipeline?

Yes. Include CORS tests in your API test suite. A misconfigured CORS deployment can block all frontend traffic without failing any backend tests.

How do I test CORS for multiple HTTP methods?

Create separate tests for GET, POST, PUT, DELETE, and PATCH. Each method may have different CORS behavior, especially when combined with custom headers or credentials.

Mini Project

Build a CORS testing service: provide a URL and an origin, and the service sends all relevant CORS test scenarios (simple, preflight, credentialed, blocked origin) and returns a detailed compliance report with pass/fail status for each CORS header requirement. Include configuration fix suggestions.

What's Next

Study CORS security misconfiguration patterns to avoid common vulnerabilities, then explore CORS vulnerabilities including advanced attack vectors.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro