# CORS Config Review

CORS Config Review is a tested SKILL.md that reviews CORS code or server configuration (an Express or Flask handler, an nginx block, a framework setting) for the five mistakes that let a hostile web page read private responses, and lists only those, one line each with a fixed code, the place, why it is dangerous and the fix - or exactly No findings; an agent buys it once for $0.01 over x402.

- Page: https://aiskills402.com/skills/cors-config-review
- Category: Code & Engineering (https://aiskills402.com/categories/code)
- Price: $0.01 once, USD-priced, paid in USDC on Base over x402. Price as loaded on this page. The 402 response your agent receives is authoritative.
- Version: 1.0.0
- Card (JSON): https://api.aiskills402.com/v1/skills/cors-config-review

## Use it when

Reviews CORS code or server configuration (an Express or Flask handler, an nginx block, a framework setting) for the five mistakes that let a hostile web page read private responses, and lists only those, one line each with a fixed code, the place, why it is dangerous and the fix - or exactly No findings. It catches a request Origin copied into the allow header while cookies are allowed, a wildcard origin together with credentials, the null origin allowed, an origin check by suffix, substring or an unanchored pattern, and a per-origin allow header sent without Vary Origin. It leaves out the safe look-alikes, such as an exact allow-list with credentials and a public read-only API that answers with a wildcard and no credentials. Use to review CORS code before release, to audit a gateway config, or to debug a browser CORS error that looks like a server mistake.

## Not for

Preflight caching, private network access, cookie flags and headers other than the cross-origin ones. It reads one pasted handler or config and judges only what is written in it.

## Tested, honestly

Tested 2026-10-19.

- Strong model (claude-sonnet-5-5 (Claude Code alias "sonnet")): Right on all 3 cases, read by hand. On the Express handler it gave the suffix check and the missing Vary and left out the public status route. On the nginx file it gave the reflected origin in the upload location and the null entry in the map, and left out the exact allow-list. On the clean Flask handler it answered exactly No findings.
- Weak model (claude-haiku-5-5 (Claude Code alias "haiku")): Right on 2 of 3 cases, read by hand. It was right on the nginx file and on the clean Flask handler. On the Express handler it gave the suffix check and the missing Vary but also an origin-reflected line, although a comparison exists, and a wildcard-with-credentials line for the status route. The second remark is defensible, because the global middleware sets the credentials header before that route sets the star for a matching origin, so our bait was not fully clean; the reflection line contradicts the skill definition. The check counts both as misses and it is recorded as a wrong answer.

Note: Light test: three cases (two planted, one clean), one run per model; no comparison without the skill. The three inputs were written by us; each planted one carries a safe look-alike and neither planted case has a comment pointing at the defect. Facts come from public documentation, read on 19 October 2026; there are no owner-measured facts. One input (the Express handler) turned out to carry an unintended second defect in the bait, disclosed in the verdicts.

Full summary: https://aiskills402.com/skills/cors-config-review/tests

## Example

### English (claude-sonnet-5-5)

Before:

> const express = require('express'); const app = express(); app.use((req, res, next) => {   const origin = req.headers.origin || '';   if (origin.endsWith('example.com')) {     res.setHeader('Access-Control-Allow-Origin', origin);     res.setHeader('Access-Control-Allow-Credentials', 'true');   }   next(); });…

After:

> WEAK-ORIGIN-CHECK — global middleware, `origin.endsWith('example.com')` — a hostile site such as `evilexample.com` or `example.com.evil.com`-style lookalikes ending in `example.com` passes the check and gets credentialed read access to `/api/orders` — parse the origin and compare it against an exact list of full origins (e.g. `https://app.example.com`) or an anchored, escaped pattern…

## What is in the file

- What the MDN page says, as published on 19 October 2026
- The answer
- The codes
- Rules
- Work in this order
- Short example

## Languages

English

## How to buy

Agent (HTTP):

1. GET https://api.aiskills402.com/v1/skills/cors-config-review/file without a payment header. The answer is 402 with a PAYMENT-REQUIRED header (x402 v2): exact amount, asset, network, recipient.
2. Sign `accepts[0]` with an x402 client (for example @x402/core + @x402/evm).
3. Repeat the GET with the signature in the PAYMENT-SIGNATURE header. The answer is 200 with the file, its sha256 and a re-download token.

Agent (MCP): https://mcp.aiskills402.com/mcp — free tools search_skills, get_skill, redownload_skill. Buying itself is over HTTP.

Full flow: https://aiskills402.com/docs

## The file

- Version: 1.0.0
- Size: 6.2 KB (6376 bytes)
- SHA-256: d297c9e8bd064e60a9f5ac9e7e12d853e73054e8ae4cf4f59b48b47944763648
- Updated: 2026-10-19
- New versions are free through your re-download token.

## Versions

### 1.0.0 (2026-10-19)

First release, written in the light-test batch of 19 October 2026 (three cases, price $0.01). The idea is ours; no foreign skill was opened, facts come from public documentation (see notes/ideas.md). Output: see the skill description.

Test: three cases written by hand (two planted, each with a safe look-alike, one clean control), one run on Claude Sonnet and one on Claude Haiku, no run without the skill, no iteration on the skill text after the runs. `test/control.mjs` shows that the checks pass on the ideal answers and fail on realistic wrong ones. See `test-summary.json` for the verdicts read by hand.

## License

Perpetual, non-exclusive; use and modify for yourself incl. paid work; no resale or republishing. Holder: Georgi Kalchev, aiskills402.com. Terms: https://aiskills402.com/docs#license

## FAQ

### Star origin on a public read-only route: a finding?

Only when credentials are allowed on the same response. A public read-only route that answers with the star and sets no cookie header is a normal setup and gets no line.

### Is an exact allow-list with credentials reported?

No. Copying the request origin after a match against a set of full origins, with Vary Origin sent, is the safe form and gets no line. Copying the origin with no comparison is reported as reflection.

### What is the rule for the null origin?

MDN notes that the origin can be the word null and offers no rule for it. Treating null as an allowed origin on a response with credentials is therefore the own policy of this skill, and its text says so openly.

### Where did the test go wrong?

An Express handler with an ends-with check and no Vary, an nginx file with a null entry and one location that copies the origin, and a clean Flask handler. Claude Sonnet was right on all three. Claude Haiku was right on two and on the Express handler added a reflection line and a wildcard line; the second is defensible because the global middleware also runs on the status route, so that bait was not clean.

## Measurement limits

- Models other than the two named above were not run.
- Each verdict comes from the test run on the date shown; the skill may have changed since (check the version).
- Full test inputs are not published here, only short excerpts of our own text.
- Results on your own texts, languages and domains can differ.

Offer note: Paid in USDC (USD-pegged) over x402 by an AI agent; one-time.
