Describe the Issue:
A Nessus scan reported that the OpenSearch HTTPS endpoint is missing the Strict-Transport-Security (HSTS) header (RFC 6797). As a result, the server does not enforce HTTPS, which may expose it to downgrade or SSL stripping attacks.
Configuration:
HTTPS enabled
OpenSearch Security (Basic Authentication)
HSTS header not present in HTTPS responses
Relevant Logs or Screenshots:
Nessus Plugin ID: 142960 – HSTS Missing From HTTPS Server (RFC 6797)
@mohit24 thats a great find. I’d encourage you to open a GitHub issue on opensearch-project/security requesting configurable HSTS header injection. The Security plugin already adds some security response headers (e.g. X-Frame-Options, X-Content-Type-Options), HSTS would be a natural addition there, likely gated on plugins.security.ssl.http.enabled: true
As a workaround for now, you can add the header at the reverse proxy / load balancer layer in front of OpenSearch.
Hi, @Anthony , a possible solution is to place a reverse proxy or load balancer in front of OpenSearch and route all client and Nessus traffic through it instead of allowing direct access to the OpenSearch API. Simply changing the OpenSearch port from 9200 to 9201 will not resolve the issue because Nessus scans the OpenSearch API directly and will detect the same finding if the new port is accessible. Configuring network.host: 127.0.0.1 is also not an option in our environment because we have a multi-node OpenSearch cluster.
@mohit24 The reverse proxy approach actually works at the cluster level, not per-node, so it scales cleanly to multi-node setups. A single nginx/HAProxy/ALB instance sits in front of the cluster and handles all inbound traffic, the HSTS header gets injected there regardless of how many data nodes are behind it. You don’t need a proxy on each node.
That said, if you’re looking for OpenSearch-native alternatives (i.e., no proxy at all): there is currently no opensearch.yml or Security plugin setting to inject arbitrary HTTP response headers like Strict-Transport-Security. The Security plugin hardcodes a handful of security headers but HSTS is not among them.
@Anthony We tested both single-node and multi-node OpenSearch deployments.
Single-node deployment: Configuring OpenSearch to listen on 127.0.0.1:9201 and placing NGINX in front on port 9200 works successfully. NGINX injects the Strict-Transport-Security (HSTS) header, and Nessus does not report the HSTS Missing From HTTPS Server (RFC 6797) vulnerability because all traffic is routed through NGINX.
Two-node OpenSearch cluster: The same approach is not supported. Setting network.host: 127.0.0.1 on the cluster nodes prevents them from communicating with each other, resulting in cluster formation failure, no cluster manager election, and the Security plugin remaining uninitialized. As a result, the cluster becomes unavailable.
The logs confirm this behavior:
[WARN ] ClusterFormationFailureHelper
cluster-manager not discovered or elected yet...
have discovered:
{SEREVR..} ... {127.0.0.1}{127.0.0.1:9300}
discovery will continue using:
SERVERIP1:9300
SEREVRIP2:9300
[ERROR] OpenSearch Security not initialized. Cluster manager not present
Therefore, for a multi-node OpenSearch cluster, binding OpenSearch to 127.0.0.1 is not a viable solution. The only practical remediation is to deploy a central reverse proxy or load balancer in front of the cluster and ensure that all client and Nessus traffic is routed through it. If Nessus continues to access the OpenSearch API directly, the HSTS header cannot be injected because OpenSearch does not currently provide native support for adding the Strict-Transport-Security (HSTS) header.
Please let us know if there are any other possible solutions that we can evaluate.