Skip to main content
Technical Deep DiveHidden Blocker

CORS and Agent Readiness: Why Cross-Origin Headers Determine If AI Agents Can Use Your API

Your API works perfectly in Postman. It passes every test in your CI pipeline. But when an AI agent tries to call it from a browser-based runtime, it silently fails. The culprit: CORS headers. Cross-Origin Resource Sharing is the invisible gatekeeper that determines whether agents running outside your domain can interact with your endpoints.

AH
AgentHermes Research
April 16, 202613 min read

CORS Blocks Agents by Default

CORS was designed to protect humans. When a browser loads a page from domain A and that page tries to call an API on domain B, the browser checks whether domain B explicitly allows cross-origin requests. If it does not, the browser blocks the request entirely. This prevents malicious websites from making unauthorized API calls using a visitor's cookies.

The problem is that AI agents are not malicious websites. They are legitimate programmatic clients that need to call your API from their own origin — which is, by definition, different from yours. An agent running inside a browser extension, an Electron app, a WebAssembly sandbox, or any JavaScript-based agent framework will hit CORS restrictions on every API that was not configured to allow cross-origin access.

In our scan of 500 businesses, we found that over 60% of APIs that return proper JSON responses still fail agent integration tests because of CORS misconfiguration. The API itself works — the headers around it do not.

60%+
of APIs block agents via CORS
0
CORS errors visible in server logs
22%
score weight affected (D7+D9)
5 min
to fix in middleware

The Four CORS Problems That Block AI Agents

Each of these misconfigurations silently prevents agents from using your API. None of them produce server-side errors — the failure happens entirely in the client.

Origin-locked CORS

CRITICAL severity

Access-Control-Allow-Origin set to a single domain like https://app.example.com. Any request from a different origin — including an AI agent running on a cloud server — gets blocked with a CORS error before the request body is even read.

Impact: Agent cannot call any endpoint

Missing Authorization in allowed headers

CRITICAL severity

Access-Control-Allow-Headers does not include Authorization. The browser (or agent HTTP client respecting CORS) strips the Bearer token from the request. The API receives an unauthenticated call and returns 401.

Impact: Agent authenticates but token is stripped

Broken OPTIONS preflight

HIGH severity

The server does not respond to OPTIONS requests, or responds with a 405 Method Not Allowed. Preflight fails, the actual request never fires. This is invisible in curl testing because curl skips preflight.

Impact: Agent blocked before request sends

Rate-limit headers not exposed

MEDIUM severity

Access-Control-Expose-Headers does not include X-RateLimit-Remaining, X-RateLimit-Limit, or Retry-After. The agent cannot read these headers even when they exist in the response, so it cannot self-throttle.

Impact: Agent hits rate limits blindly

Agent-Blocking vs Agent-Ready CORS Headers

A side-by-side comparison of CORS configurations that block agents versus configurations that allow them. Every header listed here is part of what AgentHermes checks during a scan.

Header
Blocks Agents
Agent-Ready
Access-Control-Allow-Origin
https://app.example.com
* or dynamic per-request origin validation
Access-Control-Allow-Headers
Content-Type only
Content-Type, Authorization, X-Request-ID
Access-Control-Allow-Methods
GET, POST only
GET, POST, PUT, PATCH, DELETE, OPTIONS
Access-Control-Expose-Headers
Not set
X-RateLimit-Remaining, X-RateLimit-Limit, X-Request-ID, Retry-After
Access-Control-Max-Age
Not set (preflight every request)
86400 (cache preflight for 24 hours)
OPTIONS response
405 Method Not Allowed
204 No Content with full CORS headers

The wildcard trap: Setting Access-Control-Allow-Origin: * but omitting Authorization from Allow-Headers is the most common anti-pattern. The agent can reach your server but cannot authenticate. The API returns 401 on every request. From the agent's perspective, your API requires credentials it cannot send.

The 5-Minute Fix: Agent-Ready CORS Middleware

The fix is a single middleware function that runs before every API response. It adds the correct CORS headers and handles OPTIONS preflight requests. Here is what it needs to do:

1

Set Access-Control-Allow-Origin dynamically

Read the request Origin header. If it matches your allowlist (or you allow all origins for public APIs), echo it back. For APIs secured by Bearer tokens, wildcard (*) is safe because auth is in the header, not cookies.

2

Include Authorization in Allow-Headers

Add Content-Type, Authorization, X-Request-ID, and any custom headers your API uses to Access-Control-Allow-Headers. Without Authorization, agents cannot send Bearer tokens cross-origin.

3

Expose rate-limit and request-ID headers

Add X-RateLimit-Remaining, X-RateLimit-Limit, X-Request-ID, and Retry-After to Access-Control-Expose-Headers. These are invisible to cross-origin clients unless explicitly exposed.

4

Handle OPTIONS preflight with 204

Intercept OPTIONS requests and return 204 No Content with all CORS headers. Do not route OPTIONS through your auth middleware — preflight requests do not carry credentials.

5

Cache preflight with Max-Age

Set Access-Control-Max-Age to 86400 (24 hours). This tells clients to cache the preflight result, reducing latency for agents that make repeated calls to the same endpoint.

This entire configuration fits in 15-20 lines of middleware code regardless of your framework. Express, Next.js, FastAPI, Rails — every framework has a standard way to set response headers. The time investment is minimal. The impact on agent accessibility is immediate.

How Top Scorers Handle CORS

The highest-scoring businesses in our 500-business scan all have proper CORS configuration. It is not a coincidence — agent-ready APIs are built to be called from anywhere.

Stripe

CorrectScore: 68

Dynamic origin validation, Authorization exposed, proper OPTIONS, rate-limit headers in Expose-Headers. Agents call Stripe APIs from any origin without CORS failures.

Resend

CorrectScore: 75

Wildcard CORS on public endpoints, Bearer token in allowed headers, X-RateLimit-* exposed. The only Gold-tier business — CORS is part of why.

Supabase

CorrectScore: 69

REST and Realtime endpoints allow cross-origin. apikey and Authorization both in Allow-Headers. PostgREST returns proper preflight responses.

GitHub

PartialScore: 67

API endpoints return proper CORS for OAuth apps. Fine-grained PATs work cross-origin. GraphQL endpoint has stricter CORS — agents must use REST for reliability.

Security Is Not an Excuse to Block Agents

The most common objection to relaxing CORS is security. Teams worry that allowing cross-origin requests opens them to attacks. This concern is valid for cookie-based authentication — but irrelevant for agent-ready APIs that use Bearer tokens.

Here is why: CORS prevents the browser from sending cookies to a cross-origin server without consent. That matters because cookies are ambient credentials — they get attached automatically. Bearer tokens are explicit credentials — the client must deliberately include them. A malicious site cannot steal a Bearer token from another origin because it never had access to the token in the first place.

Agent-ready APIs should use proper rate limiting, Bearer token authentication, and request validation — not restrictive CORS — as their security layer. CORS is an access control mechanism for browsers, not an API security strategy.

Cookie auth + permissive CORS = Dangerous

If your API uses cookies for auth (session cookies, JWT in cookies), restrictive CORS is necessary to prevent CSRF. But cookie-based auth is not agent-ready anyway — agents cannot log in via a browser session.

Bearer auth + permissive CORS = Safe

If your API uses Authorization: Bearer tokens, permissive CORS adds zero risk. The token is never automatically attached — the caller must explicitly include it. This is the agent-ready pattern.

Frequently Asked Questions

Do AI agents actually hit CORS errors?

Yes and no. Server-side agents making raw HTTP requests (like curl) bypass CORS entirely because CORS is enforced by browsers. But many AI agent frameworks run in browser-adjacent environments — Electron apps, browser extensions, WebAssembly runtimes, and JavaScript-based agent frameworks. These environments enforce CORS. Additionally, agent developers testing in browsers during development hit CORS immediately. A properly configured CORS policy costs nothing and removes a class of integration failures.

Should I just set Access-Control-Allow-Origin to * (wildcard)?

For public API endpoints that require authentication via Bearer tokens — yes, wildcard is fine. The security comes from the token, not the origin. The anti-pattern is wildcard CORS plus cookie-based auth, which enables CSRF attacks. If your API uses Authorization headers (which agent-ready APIs should), wildcard CORS is both safe and agent-friendly.

How does CORS affect my Agent Readiness Score?

CORS configuration impacts two dimensions: D7 Security (12% weight) and D9 Agent Experience (10% weight). A properly configured CORS policy that allows cross-origin requests with Authorization headers contributes to both. A misconfigured CORS policy that blocks legitimate agent requests lowers D9 because the API is unusable from standard agent environments.

What is the Access-Control-Expose-Headers header?

By default, browsers only expose a small set of "simple" response headers to JavaScript (and therefore to browser-based agents). Headers like X-RateLimit-Remaining, X-Request-ID, and Retry-After are hidden unless you explicitly list them in Access-Control-Expose-Headers. Without this, an agent calling your API from a browser environment cannot read rate-limit information — it flies blind and hits 429 errors it could have avoided.


Is your CORS configuration blocking agents?

Run a free Agent Readiness Scan to check your CORS headers, security configuration, and 27 other signals across all 9 dimensions.


Share this article: