Exposed Elasticsearch (Port 9200)
detect, harden, and verify closure
Internet-facing Elasticsearch (or OpenSearch) on TCP 9200 with the security plugin disabled, weak authentication, an outdated build still affected by Log4Shell or older Groovy and Painless sandbox escapes, or a permissive cloud security group is one of the most consistently exploited data-exposure paths in cloud, container, and on-premise estates. Tens of thousands of unauthenticated Elasticsearch clusters have been wiped, ransomed, or copied in successive sweeps since 2017, and several of the largest publicly documented breaches of the last decade trace back to a single open index. Learn how to detect Elasticsearch exposure, lock it down, and keep the closure verifiable.
No credit card required. Free plan available forever.
What is exposed Elasticsearch?
Exposed Elasticsearch is the cluster of weaknesses that turn an Elasticsearch (or OpenSearch) data store into a direct data-breach, ransomware, and remote-code-execution path. The most common shape is an internet-facing listener on TCP 9200 (the HTTP REST API) or TCP 9300 (the transport layer) with X-Pack or OpenSearch security plugins disabled, no TLS between client and node, no role-based access control on indices, an outdated engine build behind the upstream support window, or a permissive cloud security group that opens the port to the public internet during a migration that nobody narrowed back down.
Internal-only Elasticsearch and OpenSearch clusters are not safe by definition either. Lateral movement from a compromised application host, a misconfigured Kibana, OpenSearch Dashboards, or Grafana proxy, a vendor-managed log-shipper that reaches the wrong subnet, or a developer-built side cluster that joins production by accident all read the same misconfigurations as a public attacker would. Sister exposures land on the same hosts: an internet-facing SSH listener or an exposed MongoDB instance is often what gives the attacker the foothold from which the open Elasticsearch index gets enumerated and copied.
The track record is unambiguous. The 2017 Elasticsearch ransomware sweeps wiped or held tens of thousands of unauthenticated instances. The 2020 Meow attacks scripted indiscriminate deletion of exposed Elasticsearch, MongoDB, Redis, and Cassandra without even leaving a ransom note. Successive CISA, FBI, NCSC, and ENISA advisories continue to flag exposed database and search services among the leading initial-access and data-theft enablers. Shodan and Censys index tens of thousands of Elasticsearch listeners on TCP 9200 at any moment, the operators of those scans publish public dashboards, and several of the largest publicly documented breaches of the last decade (hundreds of millions of customer records each) trace back to a single open Elasticsearch index that nobody currently owned.
Exposed Elasticsearch is also a recurring audit and cyber-insurance finding. PCI DSS Requirement 1.3, 2.2, 8.3, and 8.4, ISO 27001 Annex A.5.15, A.8.5, A.8.20, A.8.21, A.8.24, and A.8.25, NIST SP 800-53 SC-7 and IA-2, the CIS Critical Security Controls v8.1 Control 3, Control 4, and Control 13, GDPR Articles 32 to 34, HIPAA 45 CFR 164.312, and most cyber-insurance questionnaires either prohibit or restrict direct internet exposure of search and database services and require documented hardening of those that remain. Closing the exposure or hardening the listener is usually inexpensive compared to the operational, regulatory, and reputational cost of leaving it open, which is why this class of finding tends to move quickly through remediation tracking once it is surfaced on a controlled record.
How attackers exploit it
Discover open 9200
Attackers continuously scan IPv4 (Shodan, Censys, Masscan, ZMap, custom scanners) for hosts answering HTTP on TCP 9200, the transport port on TCP 9300, and the Kibana and OpenSearch Dashboards ports on TCP 5601. The Elasticsearch root response advertises the cluster name, the engine version, the Lucene version, the tagline, and the build hash before any credential is submitted, giving the attacker enough fingerprint to pick a CVE.
Probe authentication state
Tooling (curl, elasticsearch-py, custom Go and Python clients) checks whether the listener accepts unauthenticated requests against /_cluster/health, /_cat/indices, /_cat/nodes, and /_security/user. Where security is disabled the attacker enumerates every index, mapping, and document count without ever submitting a username. Where security is on but weak, automated brute-force or credential-stuffing tooling replays leaked breach corpora against the basic-auth header.
Exfiltrate, ransom, or wipe
Once authenticated or where no credential is required, attackers run GET /_search?size=10000 against high-value indices, page through every document, copy the data to attacker storage, drop or rename the original indices, and leave a ransom note (a "README" or "PLEASE_READ" index) demanding cryptocurrency for return. Meow-class attackers skip the ransom step and overwrite the indices with random data.
Achieve code execution and pivot
On older builds (notably the long-tail of Log4Shell-affected versions, the Groovy and Painless sandbox escapes, the path-traversal and SSRF classes in the search and snapshot APIs, and the unauthenticated remote code execution chains historically tracked under CVE-2014-3120, CVE-2015-1427, CVE-2015-3337, and the 2021 Log4j family), attackers chain the open listener into remote code execution, then pivot to peer nodes, harvest credentials from configuration files and environment variables, and stage ransomware or large-scale data exfiltration through the same channel.
Common causes
Cloud security group rule too broad
An AWS security group, Azure NSG, GCP firewall rule, or DigitalOcean rule opens TCP 9200 to 0.0.0.0/0 during a Terraform run, a Helm install, a migration, a debug session, a vendor handoff, or a log-pipeline recovery exercise. The rule is never narrowed, and a public Elasticsearch listener persists across image rebuilds, autoscaling events, cluster recovery, and account migrations.
Security plugin disabled
xpack.security.enabled is set to false in elasticsearch.yml (or plugins.security.disabled is set to true on OpenSearch) to make a development build start cleanly, the setting survives into production, and the cluster accepts every request without authentication. The legacy Shield plugin or older Search Guard is unconfigured. Anonymous access is permitted by default on cluster bring-up and never closed.
network.host bound to 0.0.0.0
network.host is set to 0.0.0.0, _site_, or an external interface name in elasticsearch.yml or as the network.host environment variable in a container image. The listener answers on every interface rather than the private cluster network. The discovery transport on 9300 inherits the same bind, exposing the inter-node protocol to anyone who can reach the host.
Outdated Elasticsearch or OpenSearch build
Long-lived virtual machines, frozen container images, vendor-distributed appliances, and home-grown installs run an engine release several years behind the upstream support window. End-of-life branches receive no security backports. The Log4j 2.x family (CVE-2021-44228, 45046, 45105, and 44832) still resolves to vulnerable jars across legacy 6.x and unpatched 7.x clusters. Historic remote code execution CVEs (CVE-2014-3120, CVE-2015-1427, CVE-2015-3337) and the Groovy and Painless sandbox escapes remain exploitable on aged builds.
Reverse proxy or Kibana exposes the cluster indirectly
Elasticsearch sits behind a Kibana, OpenSearch Dashboards, Grafana, or nginx reverse proxy that itself terminates on a public load balancer with no authentication, weak basic auth, an allowlisting rule that catches more callers than intended, or a path that forwards arbitrary REST queries upstream. The Elasticsearch listener stays bound to a private interface, but the proxy turns the cluster into a public endpoint anyway.
No TLS on REST or transport
xpack.security.transport.ssl.enabled and xpack.security.http.ssl.enabled are off (or the OpenSearch plugins.security.ssl.* equivalents). Cluster traffic between nodes and queries from clients travel as plaintext. A network attacker who reaches the same subnet, a misrouted VPC peering route, or a compromised side host reads queries, basic-auth headers, and document responses directly off the wire and replays a session.
How to detect it
Automated detection
- SecPortal's external scanner port-scan module probes TCP 9200, 9300, and 5601 across every verified domain and host in scope, identifies the responding service as Elasticsearch, OpenSearch, Kibana, or OpenSearch Dashboards through banner and HTTP response detection, and raises a critical-severity finding under the rule that search and database services should never be directly exposed to the internet.
- Continuous monitoring re-runs the external scan on a schedule, so a security-group edit, a Terraform apply, a cluster recovery, an autoscale event, or a recovered backup host that re-exposes 9200 reopens the finding rather than leaving the regression invisible until the next audit cycle.
- Bulk import accepts Nessus, Burp, and CSV output from network-tier scanners and from Shodan and Censys exports that already list exposed Elasticsearch and OpenSearch instances, so the catalogue stays centralised even when a third-party tool is the original discovery source.
Manual verification
- Use nmap -p 9200,9300,5601 with service detection (-sV) and the http-elasticsearch-head script against the external range to confirm the listener, then issue curl http://target:9200/ to read the cluster name, the engine version, the Lucene version, the tagline, and the build hash from the root response without sending a credential.
- Request /_cluster/health, /_cat/indices?v, /_cat/nodes?v, and /_security/user against each reachable listener. A 200 response without authentication on any of these paths is the definitive proof of an unauthenticated cluster.
- Cross-reference the Elasticsearch or OpenSearch version banner against the vendor security advisory page, the Apache Log4j 2 advisory feed, and the CISA Known Exploited Vulnerabilities catalogue to identify whether any unpatched CVE (Log4Shell, Groovy or Painless sandbox escape, snapshot path traversal, server-side request forgery in search) is present.
- Check Shodan and Censys for the organisation's netblocks and known hostnames to see whether external observatories already list exposed Elasticsearch instances and the banners they advertise, then reconcile that list against the verified-domain inventory inside the workspace.
How to fix it
Remove direct internet exposure
Block TCP 9200, 9300, and 5601 (and any custom REST or transport port, plus any Kibana, OpenSearch Dashboards, Grafana, or head-plugin port) inbound at the perimeter firewall, the cloud security group, and the load balancer for every host. There is no production scenario where a long-lived Elasticsearch listener should be reachable from 0.0.0.0/0. Reach the cluster through a private subnet, a VPC peering or PrivateLink endpoint, a managed bastion service, or a zero-trust access broker.
Enable the security plugin and require authentication
Set xpack.security.enabled to true in elasticsearch.yml (or plugins.security.disabled to false on OpenSearch). Remove anonymous access. Reset the elastic, kibana_system, logstash_system, beats_system, and remote_monitoring_user passwords through the elasticsearch-reset-password utility (or the OpenSearch internal_users.yml). Confirm that curl http://target:9200/ without credentials returns 401 Unauthorized.
Lock network.host and the transport bind
Set network.host to a specific private interface, never 0.0.0.0 or _site_. Pin transport.host to the cluster-internal interface only. For multi-node clusters, list each peer interface explicitly in discovery.seed_hosts and cluster.initial_master_nodes. Pair the bind with a private VPC and a security group that allows only the application tier, the cluster peers, the log shippers, and the snapshot runner to reach 9200 and 9300.
Patch the engine and the Log4j surface
Apply Elasticsearch and OpenSearch updates promptly, especially advisories naming Log4Shell (CVE-2021-44228, 45046, 45105, 44832), the Groovy and Painless sandbox escapes, the historic remote code execution chains (CVE-2014-3120, CVE-2015-1427, CVE-2015-3337), and the more recent server-side request forgery and snapshot path-traversal classes. Move off end-of-life branches (5.x, early 6.x, OpenSearch 1.0.x) onto a supported version before the upstream support window closes. Validate that no legacy log4j-core-2.x jar remains pinned by a plugin or a custom integration.
Enforce role-based access control on indices
Replace the broad superuser role with purpose-scoped roles. Bind every application account to the smallest privilege bundle that lets it read or write the indices it owns. Use field-level and document-level security where the schema mixes tenant data. Audit the user list quarterly through GET /_security/user and remove accounts whose owning service or owning human has rotated.
Enable TLS on REST and transport
Set xpack.security.http.ssl.enabled and xpack.security.transport.ssl.enabled (or the OpenSearch plugins.security.ssl.* equivalents) and provide certificates signed by an internal certificate authority. Reject plaintext connections. Pair the TLS configuration with allowedHosts or client-certificate enforcement so only authorised callers can complete the handshake. Audit driver and beat versions to confirm every client supports the modern cipher suite.
Harden the reverse proxy and Kibana surface
Where Kibana, OpenSearch Dashboards, Grafana, or nginx sit in front of the cluster, require authentication on the proxy, restrict the upstream proxy_pass to a fixed set of REST paths, and disable arbitrary _scripts and _bulk forwarding from unauthenticated callers. Keep the proxy and the Elasticsearch listener on the same hardened network boundary.
Enable audit logging and monitoring
Turn on the Elasticsearch or OpenSearch audit log (xpack.security.audit.enabled, audit.logfile.events.include) for authentication events, index permissions changes, role grants, snapshot operations, and admin REST calls. Forward the audit stream to the SIEM or detection pipeline. Pair the listener with a brute-force detection rule for repeated failed authentication and a baseline rule for unexpected admin operations on the security and index APIs.
Operationalising the fix on the workspace
Closing an exposed Elasticsearch listener and re-enabling the security plugin is rarely the hard part for an experienced platform, search, or observability engineer. The operational hard part is keeping the closure intact across rebuilds, autoscaling, cluster recovery, vendor migrations, mergers and acquisitions, and the long tail of cloud accounts and on-premise hosts that nobody currently lists in a primary asset inventory. The workspace pattern below is what AppSec, cloud security, vulnerability management, data security, and security engineering teams use to keep an exposed-Elasticsearch finding from coming back six months later under a new account or a renamed host.
Surface every Elasticsearch listener on one finding record
External scanning and bulk import land every exposed-Elasticsearch detection on the findings management record with CVSS, the discovered host, the captured banner, the engine version, the Lucene version, the scan timestamp, and the named owner so the catalogue is a single source of truth rather than a Shodan tab, a spreadsheet, and a Slack thread.
Inspect cluster configuration through authenticated scans
Where the team has authorisation, the authenticated scanning path reads the responding service in more detail and pairs the result with the per-host hardening record. Credentials for authenticated runs live in encrypted credential storage scoped to a verified domain so the same cluster secret is not copied across spreadsheets, chat threads, and pull-request bodies.
Run remediation as a tracked workflow
Each finding flows through the remediation tracking workflow with severity, target close date, named owner, and the agreed compensating control (for example, an inbound source allowlist while the PrivateLink endpoint is provisioned, or a temporary firewall rule while xpack.security is enabled and passwords are reset). Permanent exceptions enter the eight-field exception register with a named approver, a rationale, an effective period, and a renewal cadence.
Verify the fix with retest
Once the firewall rule, security-group edit, elasticsearch.yml change, plugin re-enable, host retirement, or migration to a managed service completes, the retesting workflow re-runs the external scan, confirms the listener is gone or that the responding service now requires authentication on a private interface, and stamps the closure with timestamped evidence rather than a verbal sign-off in a stand-up.
Catch regressions through continuous monitoring
Scheduled continuous monitoring re-scans of verified domains reopen the finding if Elasticsearch returns to the public internet, if the banner drops back to an end-of-life build, or if a new cloud account joins the estate with an open 9200. A Terraform apply, a cluster recovery, an autoscaler refresh, a Helm chart rollback, or a recovered snapshot does not silently reintroduce the exposure.
Pair with the broader exposure catalogue
Exposed Elasticsearch rarely shows up alone. The same host frequently exposes MongoDB, SSH misconfiguration, default credentials, or sensitive data exposure. Treating Elasticsearch exposure as one finding inside a host-level posture review keeps the queue ordered against real residual risk rather than chasing isolated ports one at a time.
Carry the audit trail through closure
The activity log records who opened, scoped, remediated, and verified each exposed-Elasticsearch finding, so the next ISO 27001, SOC 2, PCI DSS, HIPAA, or cyber-insurance review reads the operating evidence from the record rather than from reconstructed memory, archived ticket exports, or screenshots taken weeks after the fact. Where a breach-notification clock starts, the breach-notification workflow reads from the same record.
Communicate posture in leadership language
When search and observability exposure sits inside a broader programme review, the Claude-drafted AI report composes a leadership-ready narrative from the open and closed findings, the remediation cadence, and the linked compliance evidence. The same record drives security leadership reporting without rebuilding the slide deck by hand each quarter.
Where the exposure usually lands
Exposed Elasticsearch is not a single shape across the enterprise estate. The conversation a cloud security team has with a platform team about a self-hosted cluster in a logging VPC differs from the conversation a data security team has with an analytics team about a managed Elastic Cloud deployment reachable from the wrong peering route. The four contexts below are the most common landing places, and each one needs a slightly different remediation playbook surfaced on the same finding record.
Self-hosted Elasticsearch on cloud VMs
EC2, Compute Engine, Azure VM, and DigitalOcean droplet deployments of community-edition Elasticsearch and OpenSearch make up the bulk of historic exposure events. Replace standing 0.0.0.0/0 security-group rules with private subnets, security-group source restrictions to application and observability tiers, and managed bastion access for human operators. Move long-lived production workloads onto Elastic Cloud, AWS OpenSearch Service, Azure Elastic, or another managed offering where the network boundary is built in and the security plugin is enabled by default.
Managed Elasticsearch with permissive access policy
Managed Elasticsearch and OpenSearch inherit the deployment defaults of whoever provisioned them. A 0.0.0.0/0 access policy on AWS OpenSearch Service, a project-wide superuser role granted by accident, an unrotated programmatic API key, an Elastic Cloud deployment with public endpoint enabled, or a peering route that reaches the wrong VPC creates the same exposure pattern as a self-hosted listener. Bind every cluster to PrivateLink, VPC peering, or a customer-managed VPC, enforce role-based access on indices, rotate programmatic API keys quarterly, and use the managed audit log as the source of truth for who connected when.
Containerised Elasticsearch in dev, test, and CI
Dockerised Elasticsearch instances inherit the official image defaults, environment-variable initialisation, and quickstart Compose files. A misrouted bridge network, a kubectl port-forward left running, an exposed service of type LoadBalancer, or an ingress-controller rule that catches more traffic than intended reopens 9200 quickly. Bake xpack.security.enabled true in the Helm chart, default to network.host 127.0.0.1 in dev compositions, and treat any LoadBalancer service for a search or logging cluster as a finding to triage.
Legacy Elasticsearch on aged builds
Long-lived virtual machines, vendor-distributed appliances, customer-managed instances at acquired companies, log-archive clusters that nobody currently owns, and home-grown installs run an Elasticsearch release several years behind the upstream support window. End-of-life branches receive no security backports. Track these hosts on the finding record with the build identifier, the Lucene version, the maintainer contact, and the upgrade path. Where the host cannot be upgraded immediately, isolate it behind a managed network access boundary and document the residual risk decision in the exception register.
Compliance impact
OWASP Top 10
A05:2021 - Security Misconfiguration; A02 - Cryptographic Failures
PCI DSS
Req. 1.3 / 2.2 / 8.3 - Boundary, Config, Strong Auth
ISO 27001
A.8.5 Secure Auth; A.8.20 Networks; A.8.24 Cryptography
NIST 800-53
SC-7 Boundary Protection; IA-2 Identification and Auth
CIS Controls v8.1
Control 3 Data Protection; Control 4 Secure Configuration; Control 13 Network Monitoring
NIST CSF 2.0
PR.AA Identity Mgmt; PR.DS Data Security
SOC 2
CC6.1 Logical Access; CC6.6 Logical Access Boundary
GDPR
Article 32 Security of Processing; Article 33 Notification
Where Elasticsearch posture lands inside the team
Exposed Elasticsearch sits across several teams at once. The internal security team owns the policy, the audit response, and the breach-notification posture. The cloud security team owns the cloud-account perimeter, the security-group baseline, and the PrivateLink architecture. The data security team owns the encryption controls, the role bundles, and the audit-log review. The vulnerability management team owns the backlog, the prioritisation, and the SLA. The security engineering team owns the hardening tooling and the identity federation path. SecPortal keeps the same finding visible to all of them on the workspace record so the handoffs do not lose context as the work moves between owners.
Related features
Vulnerability scanning tools that map your attack surface
Test web apps behind the login
Monitor continuously catch regressions early
Vulnerability management software that tracks every finding
Verify fixes and track reopens on the same finding record
Bulk finding import bring your scanner data with you
Finding overrides that survive every scan cycle
Compliance tracking without a full GRC platform
Every action recorded across the workspace
AI-powered reports in seconds, not days
Find every exposed Elasticsearch cluster across your estate before someone else does
SecPortal's external scanner probes TCP 9200, 9300, and 5601 across verified domains, identifies responding Elasticsearch, OpenSearch, Kibana, and OpenSearch Dashboards services, raises a critical-severity finding with port, service, and version evidence, tracks remediation through closure, verifies the fix through retest, and re-runs continuously so a security-group edit, a Terraform apply, a Helm rollback, or a recovered snapshot does not silently re-expose the cluster. Start free.
No credit card required. Free plan available forever.