The comments converged on a cleaner mental model. The default security feature is the Same-Origin Policy, which keeps one site’s JavaScript from freely reading another site’s data. CORS is the opt-in escape hatch that lets a server relax that default for selected origins. That makes CORS feel inverted to developers because it is not normal server-side authorization. It is the browser enforcing rules on behalf of the user. Outside the browser, `curl`,
Playwright, proxies, or a modified client can ignore it completely. That is why people keep calling it fake or useless security. The more grounded view was that it is useful for the threat it actually targets, which is malicious or compromised web pages running in a real user’s browser with that user’s cookies and ambient authority attached.
A lot of confusion came from the legacy exceptions. Browsers have always allowed certain cross-origin actions that old HTML forms and tags could already do, so “simple requests” still go out without preflight. That means GET is never a safe place to hide side effects, and some POST requests can still happen cross-origin if they use form-compatible content types like `
application/x-www-form-urlencoded`, `
multipart/form-data`, or `
text/plain`. Several commenters pointed out that this is where teams get burned. They assume “our
JSON API is protected by CORS,” then forget to strictly reject the wrong content type, or they parse JSON bodies without caring what the header said. In that case an attacker can sometimes send valid JSON through a form-compatible request path and bypass the expected preflight barrier.
The practical consensus was blunt. If an endpoint changes state, do not expose it via GET. If an endpoint expects JSON, enforce `application/json` and return `
415` for anything else. Do not assume preflight is a security boundary unless your endpoint design actually depends on methods and headers that require preflight. And if you can keep frontend and backend on the same origin with a reverse proxy, you dodge a lot of this complexity entirely. People also called out terrible browser error messages and poor docs as part of the problem, but the strongest recurring claim was simpler: many developers never learned the Same-Origin Policy first, so they experience CORS only as an annoying browser error and end up cargo-culting allow-all headers until something works.