Service:
Elasticsearch (elasticsearch daemonHTTP REST API)Protocol:
TCPPort:
9200Used for:
Elasticsearch's HTTP REST API for searching, indexing, and cluster administration over JSONPort 9200 is the default port for the Elasticsearch HTTP REST API — the JSON-over-HTTP interface every client, dashboard, and admin uses to search, index, read, write, and administer an Elasticsearch cluster. Everything you can do to the data lives behind this one port: GET /_cat/indices lists every index, GET /_search returns documents, GET /_cluster/health reports cluster state, and PUT/POST/DELETE create, modify, or wipe data. It is distinct from port 9300, the binary transport protocol nodes use to talk to each other and form the cluster — 9300 is node-to-node, 9200 is the human/application front door. The reason port 9200 dominates breach headlines is brutally simple: for most of Elasticsearch’s history it shipped with no authentication whatsoever, so an internet-reachable 9200 meant anyone could read and destroy every index with an unauthenticated curl.
Why It’s Open
Elasticsearch is the search and analytics engine at the heart of the ELK/Elastic Stack (Elasticsearch, Logstash, Kibana), and it powers logging pipelines, site search, security analytics (SIEM), APM, and product catalogues. Applications and the Kibana dashboard reach the cluster over the REST API on 9200, so the port is legitimately open on any host running a node.
The problem is historical defaults. Free/open-source Elasticsearch shipped with security disabled by default for years — the paid Shield/X-Pack add-on carried authentication and TLS, but the community distribution had none, and pre-1.2 builds even enabled remote dynamic scripting out of the box. Basic authentication and TLS only became free and on-by-default in Elasticsearch 7.x (opt-in from 6.8/7.1) and mandatory-by-default in 8.0. That leaves an enormous installed base of older, unauthenticated clusters, plus fresh 8.x nodes where an admin ran into a TLS error and “fixed” it by turning security off. Add cloud VMs and containers that bind 0.0.0.0:9200 instead of localhost, and the result is tens of thousands of open, unauthenticated Elasticsearch clusters facing the internet at any given moment.
Common Risks
- No authentication by default. On community builds before 8.0 (and any node where
xpack.security.enabled: false), the REST API on 9200 is wide open.GET /_cat/indices?v,GET /_search, andGET /_cluster/healthall return data with no credentials — full read of every index. - Full read/write/delete of all data. The same open API accepts
PUT,POST, andDELETE. An attacker doesn’t just exfiltrate documents; they can modify records, create indices, and issueDELETE /*to wipe the entire cluster. - Ransom and destruction. Because a wipe is a single unauthenticated request, open Elasticsearch became a mass-ransom target: indices deleted, a ransom note left behind as a new index demanding Bitcoin (see Real-World Example).
- Remote code execution via scripting. Older versions with dynamic scripting enabled allow arbitrary Java/Groovy/MVEL execution through the
_searchAPI, turning a data-exposure bug into full host compromise (CVE-2014-3120, CVE-2015-1427 below). - Sensitive data exposure. Elasticsearch is a favourite store for logs, PII, credentials, session tokens, medical and financial records — exactly the high-value data that shows up in the open clusters found by mass scanners.
- Cluster reconnaissance and pivot.
GET /,GET /_nodes, andGET /_cluster/settingsleak version, OS, node IPs, JVM details, and the internal 9300 transport topology — a map for lateral movement. - Unauthenticated denial of service. Even fully patched-for-RCE clusters can be crashed by malformed requests on 9200 (CVE-2023-31418).
Want to save time on reporting?
Let PentestPad generate, track, and export your reports - automatically.

Enumeration & Testing
Elasticsearch speaks plain JSON over HTTP, so curl is your primary tool — no special client needed. Start by confirming the service and version, then walk the diagnostic APIs.
Detect the service and version
nmap -sV -p 9200,9300 <target>Scanning 9300 alongside 9200 confirms whether the transport port is also exposed (it should never be public).
Fingerprint the node (version, cluster name, build)
curl http://<target>:9200/The root document returns the version number, cluster name, Lucene version, and build — enough to decide which CVEs apply. If this responds without credentials, the cluster is unauthenticated.
List every index (the data map)
curl http://<target>:9200/_cat/indices?vRead cluster health and node layout
curl http://<target>:9200/_cluster/health?prettycurl http://<target>:9200/_nodes?prettyDump documents from an index
curl "http://<target>:9200/_search?pretty&size=10"curl "http://<target>:9200/<index-name>/_search?pretty&size=10"Check whether authentication is enforced
# A 401/403 means security is on; a 200 with data means it is not.curl -s -o /dev/null -w "%{http_code}\n" http://<target>:9200/_cat/indicesMetasploit modules (verified paths)
msfconsole -q# Enumerate indices over the REST APIuse auxiliary/scanner/elasticsearch/indices_enumset RHOSTS <target>run
# Broader gather module (indices + doc samples)use auxiliary/gather/elasticsearch_enumset RHOSTS <target>run
# Dynamic-scripting RCE (CVE-2014-3120, <1.2)use exploit/multi/elasticsearch/script_mvel_rceset RHOSTS <target>run
# Groovy sandbox-bypass RCE (CVE-2015-1427, <1.3.8 / 1.4.x <1.4.3)use exploit/multi/elasticsearch/search_groovy_scriptset RHOSTS <target>runCapture every open port 9200, the version banner, the full index list, and any documents you pull, so the evidence lands in the pentest report instead of a scratch terminal you’ll lose.
What to Look For
| Checkpoint | What it means |
|---|---|
GET / returns version JSON with no credentials |
Unauthenticated cluster — every index is readable and writable |
_cat/indices lists real indices |
Data exposure; note names hinting at PII, logs, or credentials |
_search returns documents to anonymous requests |
Confirmed full read access to that index |
PUT/POST/DELETE accepted without auth |
Full write/wipe — ransom and tampering risk |
| Version < 1.4.3 (Groovy) or < 1.2 (dynamic scripting) | Remote code execution via _search scripting |
xpack.security.enabled: false or 200 on /_cat/indices |
Security explicitly disabled — treat as critical |
| Port 9300 reachable from outside | Transport layer exposed; cluster join / node spoofing risk |
A lone index named like read_me, warning, or how_to_recover |
Cluster already ransomed/wiped by a mass scanner |
Known CVEs and Exploits
Elasticsearch’s most severe network CVEs are the scripting remote-code-execution flaws in older versions, plus directory-traversal and denial-of-service bugs. Every CVE below was verified against its NVD record and confirmed to be an Elasticsearch issue on this port.
- CVE-2015-1427 — The Groovy scripting engine in Elasticsearch before 1.3.8 and 1.4.x before 1.4.3 lets a remote attacker bypass the sandbox and execute arbitrary shell commands via a crafted script sent to
_search. CVSS 9.8 (critical) and listed in CISA’s Known Exploited Vulnerabilities catalog. Weaponised as Metasploitexploit/multi/elasticsearch/search_groovy_scriptand archived as Exploit-DB 36337. - CVE-2014-3120 — The default configuration in Elasticsearch before 1.2 enables dynamic scripting, allowing remote attackers to execute arbitrary MVEL expressions and Java code via the
sourceparameter to_search. A design-level RCE that needs no other bug — just an old default. Also in CISA’s KEV catalog; Metasploitexploit/multi/elasticsearch/script_mvel_rceand Exploit-DB 33370. - CVE-2015-5531 — Directory traversal in Elasticsearch before 1.6.1 lets a remote attacker read arbitrary files via the snapshot API. CVSS 5.0 — file disclosure rather than code execution, but a straight path to secrets on the host.
- CVE-2015-3337 — Directory traversal in Elasticsearch before 1.4.5 and 1.5.x before 1.5.2, when a site plugin is installed, allows reading arbitrary files. CVSS 4.3. Note the precondition — this is not a universal bug.
- CVE-2023-31418 — A modern, still-relevant flaw: an unauthenticated attacker can force an Elasticsearch node to exit with an OutOfMemory error by sending a moderate volume of malformed HTTP requests to 9200. Affects versions up to 7.17.12 and 8.0.0–8.8.2 (fixed in 7.17.13 / 8.9.0). CVSS 7.5 — a denial-of-service reminder that “it’s patched for the RCEs” isn’t the end of the story.
Correction to the previous version of this page. The old stub listed CVE-2015-3337 as an RCE that “allows remote attackers to execute arbitrary commands.” That is wrong — CVE-2015-3337 is a directory-traversal file-read bug that also requires a site plugin to be installed. It is kept above with its accurate description. The genuine remote-code-execution issues on this port are the scripting flaws CVE-2014-3120 and CVE-2015-1427.
Mitigation
- Enable authentication — it’s free now. On Elasticsearch 6.8+/7.x set
xpack.security.enabled: trueand configure users/roles; on 8.0+ it is on by default, so never disable it to work around a setup error. There is no scenario where an internet-reachable 9200 should accept anonymous requests. - Never expose 9200 (or 9300) to the internet. Bind to
localhostor a private interface (network.host), and put the cluster inside a VPC/security group that only application hosts can reach. Audit cloud security groups and container port maps for an accidental0.0.0.0:9200. - Front it with TLS and a reverse proxy. Terminate TLS on 443 and require auth at the proxy for any browser-facing access (Kibana included); enable TLS on the transport layer between nodes as well.
- Patch, and disable dynamic scripting on anything old. Upgrade off end-of-life 1.x/2.x/5.x; if you cannot, disable dynamic scripting to kill the CVE-2014-3120 / CVE-2015-1427 RCE path.
- Least privilege on data. Use role-based access control so an application account can read only the indices it needs and cannot
DELETE /*. - Snapshot and monitor. Keep offline snapshots so a wipe/ransom is recoverable, and alert on anomalous bulk reads, mass deletes, or the sudden appearance of a “ransom note” index.
Real-World Example
In January 2017, immediately after the wave of attacks that wiped tens of thousands of open MongoDB databases, the same crews turned on Elasticsearch. Automated scanners (using engines like Shodan) found clusters with 9200 open and no authentication, deleted every index with a one-line unauthenticated request, and left behind a new index containing a ransom note demanding Bitcoin to “restore” data that, in most cases, the attackers never actually kept. Researchers tracking the campaign (including Niall Merrigan and Victor Gevers) counted thousands of Elasticsearch clusters hijacked within days, out of the tens of thousands exposed. The episode is the definitive lesson of this port: Elasticsearch’s no-auth-by-default history meant that reading, and destroying, an entire production dataset required nothing more than knowing the IP and typing curl. The MongoDB story on 27017 and the open-Redis problem on 6379 are the same misconfiguration in different datastores.
FAQ
What is port 9200 used for?
Port 9200 is the default port for Elasticsearch’s HTTP REST API — the JSON-over-HTTP interface used to search, index, read, write, and administer an Elasticsearch cluster. Every client library and dashboard (including Kibana’s backend) talks to the cluster on 9200.
What is the difference between port 9200 and port 9300?
Port 9200 is the HTTP REST API for clients and applications; port 9300 is the binary transport protocol Elasticsearch nodes use to communicate with each other and form a cluster. You interact with 9200 using curl; 9300 is internal node-to-node traffic and should never be exposed to the internet.
Is Elasticsearch on port 9200 secure by default?
Historically, no. Community/open-source Elasticsearch shipped with no authentication for years — security lived in the paid Shield/X-Pack add-on. Free basic security (auth + TLS) became opt-in around 6.8/7.1 and on-by-default in 8.0. Anything older, or any node where xpack.security.enabled is set to false, exposes the entire dataset to anonymous requests.
How do I check if my Elasticsearch is exposed?
Run curl http://<host>:9200/ from outside your trusted network. If it returns version JSON without asking for credentials, the cluster is unauthenticated and readable. Follow up with curl http://<host>:9200/_cat/indices?v — if you see your real index names, so can anyone else who finds the IP.
Can port 9200 lead to remote code execution?
Yes, on older versions. Elasticsearch before 1.2 enabled dynamic scripting by default (CVE-2014-3120), and the Groovy engine in versions before 1.4.3 had a sandbox bypass (CVE-2015-1427) — both allow arbitrary command execution through the _search API. Patch off these versions and disable dynamic scripting if you cannot.
How do I secure port 9200?
Enable authentication (it is free and default in 8.0+), never disable X-Pack security to dodge a setup error, bind Elasticsearch to a private interface, keep 9200 and 9300 off the public internet behind a VPC/firewall, front browser access with TLS and a reverse proxy, apply least-privilege roles, and keep snapshots for recovery.
TL;DR
- Service: Elasticsearch HTTP REST API (the
elasticsearchdaemon; ELK/Elastic Stack) - Default port: 9200/TCP for the REST API (9300/TCP is the separate node-to-node transport port)
- Biggest risk: unauthenticated exposure — for years Elasticsearch shipped with no auth, so an open 9200 means full read/write/delete of every index by anyone, plus scripting RCE on old versions
- Mitigation: enable authentication (free and default in 8.0+), never disable it, keep 9200/9300 off the internet behind a VPC/firewall, front with TLS + a reverse proxy, patch off end-of-life versions, apply least-privilege roles, and keep recoverable snapshots