Do not enable Elasticsearch CORS with a wildcard
/etc/elasticsearch/elasticsearch.yml# The default and the right answer for most clusters:http.cors.enabled: false
# If a browser app genuinely needs it, name exact origins — never '*':# http.cors.enabled: true# http.cors.allow-origin: "https://app.example.com"# http.cors.allow-credentials: truesudo systemctl restart elasticsearchWhy it matters
Section titled “Why it matters”CORS decides which websites are allowed to make browser requests to your cluster. The dangerous configuration is the one that gets copied from old dashboard tutorials:
http.cors.enabled: truehttp.cors.allow-origin: "*" # any website, anywhereThat says: any web page a user visits may make requests to this Elasticsearch cluster from that user’s browser. If the cluster is reachable from the user’s network — an internal cluster and an employee browsing the web, or any cluster and an admin on the same machine — a malicious page can query indices, and if security is off, read and delete them.
It’s a specific and underappreciated way an “internal” cluster becomes reachable: you didn’t expose it to the internet, but you let the internet’s web pages reach it through the browsers of people who can.
Where it comes from
Section titled “Where it comes from”Old Elasticsearch browser tools — elasticsearch-head, dejavu, and various
homegrown dashboards — run as static pages in the browser and talk directly to the
cluster’s REST API. To work, they need CORS enabled, and the lazy configuration is
allow-origin: "*".
Those tools are largely obsolete now — Kibana talks to Elasticsearch server-side,
not from your browser, so it needs no CORS at all. But the setting outlives the
tool. A cluster that once ran elasticsearch-head in 2019 may still have
http.cors.allow-origin: "*" in its config, doing nothing useful and standing
open.
If you actually need it
Section titled “If you actually need it”Some legitimate single-page applications query Elasticsearch directly. If yours does, name the exact origins:
http.cors.enabled: truehttp.cors.allow-origin: "https://app.example.com"http.cors.allow-methods: "GET, POST"http.cors.allow-credentials: trueTwo rules:
- Never
*, and never a regex broader than you can defend.allow-originaccepts a/regex/— a sloppy one like/https?://.*\.example\.com/can matchevil.example.com.attacker.netdepending on how it’s written. allow-credentials: truecannot be combined withallow-origin: "*"by the browser’s own rules — which is a hint from the web platform that wildcard plus credentials is exactly the combination that shouldn’t exist.
Better still: put the browser app behind your own backend, which talks to Elasticsearch server-side with a scoped API key. Then the cluster needs no CORS and the key never reaches the browser.
Related
Section titled “Related”- Enable security — CORS is worst when there’s no auth behind it.
- API keys and least privilege — the server-side alternative to browser access.