{
  "format_version": 3,
  "policy": {
    "external_id": "39a6b1412d386eb774e13e9d2a9f7cb2",
    "name": "CIS NGINX Benchmark v3.0.0 - Level 1",
    "version": "1.0.0",
    "description": "CIS Level 1 hardening profile for NGINX. Module loading, non-root worker user, file ownership, server_tokens, TLS hardening, security response headers (HSTS / X-Content-Type-Options / CSP / Referrer-Policy). Assign to a system group of NGINX hosts. Config-file checks expand to /etc/nginx/nginx.conf and /etc/nginx/conf.d/*.conf.",
    "author": "Center for Internet Security"
  },
  "tests": [
    {
      "external_id": "2e7ebf2544e0fb7c0e7fc9066395b897",
      "name": "1.1.1 — Ensure NGINX is installed",
      "description": "NGINX must be installed from the official packaging.",
      "rational": "Installing NGINX from the official source ensures predictable security baselines and timely updates.",
      "remediation": "Install nginx via the distribution package manager (apt/yum) or the upstream nginx.org repository.",
      "severity": "Medium",
      "filter": null,
      "app_filter": null,
      "conditions": [
        {
          "type": "condition",
          "element": "CMD",
          "input": "command -v nginx >/dev/null && echo OK || echo MISSING",
          "selement": "OUTPUT",
          "condition": "EQUALS",
          "sinput": "OK"
        }
      ],
      "applicability": []
    },
    {
      "external_id": "04f6c7a6538f6d5cff31fa973961b651",
      "name": "2.1.1 — Ensure only required dynamic modules are loaded",
      "description": "Only modules that are required by the deployed configuration should be loaded into the running NGINX worker processes.",
      "rational": "Each loaded module enlarges the attack surface — unused modules should be removed.",
      "remediation": "Review nginx -V output and comment out any unneeded `load_module` directives in /etc/nginx/nginx.conf.",
      "severity": "Medium",
      "filter": null,
      "app_filter": null,
      "conditions": [
        {
          "type": "condition",
          "element": "CMD",
          "input": "grep -hcE '^[[:space:]]*load_module' /etc/nginx/nginx.conf /etc/nginx/conf.d/*.conf 2>/dev/null | awk '{s+=$1} END {print s+0}'",
          "selement": "OUTPUT",
          "condition": "EQUALS",
          "sinput": "0"
        }
      ],
      "applicability": []
    },
    {
      "external_id": "bb46500d172552a0433c1cebcaedec0f",
      "name": "2.2.1 — Ensure NGINX runs as a non-privileged user",
      "description": "The NGINX worker processes should run as a dedicated non-root account such as 'nginx' or 'www-data'.",
      "rational": "Running workers as a non-root user contains the blast radius of any compromise in the request handling code path.",
      "remediation": "Set the `user` directive in /etc/nginx/nginx.conf to a non-root account (e.g. `user nginx;`).",
      "severity": "Medium",
      "filter": null,
      "app_filter": null,
      "conditions": [
        {
          "type": "condition",
          "element": "CMD",
          "input": "grep -hiE '^[[:space:]]*user[[:space:]]+' /etc/nginx/nginx.conf 2>/dev/null | awk '{print $2}' | tr -d ';'",
          "selement": "OUTPUT",
          "condition": "NOT EQUALS",
          "sinput": "root"
        }
      ],
      "applicability": []
    },
    {
      "external_id": "456e90b8ecc276dd8f1f34a1510501ff",
      "name": "2.3.1 — Ensure NGINX directories and files are owned by root",
      "description": "All files and directories under /etc/nginx should be owned by root.",
      "rational": "Restricting ownership prevents unauthorised users from modifying the configuration that the privileged master process reads at startup.",
      "remediation": "Run: chown -R root:root /etc/nginx",
      "severity": "Medium",
      "filter": null,
      "app_filter": null,
      "conditions": [
        {
          "type": "condition",
          "element": "CMD",
          "input": "find /etc/nginx -not -user root 2>/dev/null | wc -l",
          "selement": "OUTPUT",
          "condition": "EQUALS",
          "sinput": "0"
        }
      ],
      "applicability": []
    },
    {
      "external_id": "7c2c0d3c50a7e973e417c0dc68b73d32",
      "name": "2.4.3 — Ensure keepalive_timeout is 10 seconds or less, but not 0",
      "description": "Keep-alive connections that idle for too long tie up worker slots and can be exploited for slow-loris style attacks.",
      "rational": "Setting keepalive_timeout to a low non-zero value frees worker slots quickly while still allowing connection reuse.",
      "remediation": "Set `keepalive_timeout 10;` (or lower, but non-zero) in /etc/nginx/nginx.conf.",
      "severity": "Medium",
      "filter": null,
      "app_filter": null,
      "conditions": [
        {
          "type": "condition",
          "element": "CMD",
          "input": "grep -hiE '^[[:space:]]*keepalive_timeout' /etc/nginx/nginx.conf 2>/dev/null",
          "selement": "OUTPUT",
          "condition": "NOT EQUALS",
          "sinput": ""
        }
      ],
      "applicability": []
    },
    {
      "external_id": "472ba2675307f7fad6f38a3ee79b4da5",
      "name": "2.5.1 — Ensure server_tokens directive is set to 'off'",
      "description": "The server_tokens directive controls whether NGINX emits its version in response headers and error pages.",
      "rational": "Hiding the version makes targeted exploitation of known vulnerabilities marginally harder for opportunistic scanners.",
      "remediation": "Add `server_tokens off;` to the http block in /etc/nginx/nginx.conf.",
      "severity": "Medium",
      "filter": null,
      "app_filter": null,
      "conditions": [
        {
          "type": "condition",
          "element": "CMD",
          "input": "grep -hiE '^[[:space:]]*server_tokens[[:space:]]+off' /etc/nginx/nginx.conf /etc/nginx/conf.d/*.conf 2>/dev/null",
          "selement": "OUTPUT",
          "condition": "NOT EQUALS",
          "sinput": ""
        }
      ],
      "applicability": []
    },
    {
      "external_id": "4256d1a23e3f0ac53223b61f7c53ef54",
      "name": "4.1.1 — Ensure HTTP is redirected to HTTPS",
      "description": "Plain HTTP traffic should be redirected to HTTPS so that all subsequent communication is encrypted.",
      "rational": "Redirecting HTTP to HTTPS prevents users from accidentally submitting credentials or session cookies in plaintext.",
      "remediation": "In the HTTP server block, add `return 301 https://$host$request_uri;`.",
      "severity": "Medium",
      "filter": null,
      "app_filter": null,
      "conditions": [
        {
          "type": "condition",
          "element": "CMD",
          "input": "grep -hiE 'return[[:space:]]+30[12].*https' /etc/nginx/nginx.conf /etc/nginx/conf.d/*.conf 2>/dev/null",
          "selement": "OUTPUT",
          "condition": "NOT EQUALS",
          "sinput": ""
        }
      ],
      "applicability": []
    },
    {
      "external_id": "97d6c767dcffc903c6e5e5913f89bf6d",
      "name": "4.1.4 — Ensure only modern TLS protocols are used",
      "description": "Only TLS 1.2 and TLS 1.3 should be enabled; SSLv2/v3 and TLS 1.0/1.1 are deprecated and vulnerable.",
      "rational": "Disabling legacy protocols protects against downgrade attacks such as POODLE and BEAST.",
      "remediation": "Set `ssl_protocols TLSv1.2 TLSv1.3;` in the http or server block.",
      "severity": "Medium",
      "filter": null,
      "app_filter": null,
      "conditions": [
        {
          "type": "condition",
          "element": "CMD",
          "input": "grep -hiE 'ssl_protocols' /etc/nginx/nginx.conf /etc/nginx/conf.d/*.conf 2>/dev/null | grep -viE 'TLSv1\\.0|TLSv1\\.1|SSLv'",
          "selement": "OUTPUT",
          "condition": "NOT EQUALS",
          "sinput": ""
        }
      ],
      "applicability": []
    },
    {
      "external_id": "83c69c2f472b33366acb9ca1a8ead763",
      "name": "4.1.8 — Ensure HTTP Strict Transport Security (HSTS) is enabled",
      "description": "HSTS instructs browsers to refuse to talk to the site over plain HTTP for the configured max-age window.",
      "rational": "HSTS mitigates SSL-stripping man-in-the-middle attacks after the first successful HTTPS visit.",
      "remediation": "Add `add_header Strict-Transport-Security \"max-age=63072000\" always;` to the https server block.",
      "severity": "Medium",
      "filter": null,
      "app_filter": null,
      "conditions": [
        {
          "type": "condition",
          "element": "CMD",
          "input": "grep -hiE 'Strict-Transport-Security' /etc/nginx/nginx.conf /etc/nginx/conf.d/*.conf 2>/dev/null | grep -v '^[[:space:]]*#'",
          "selement": "OUTPUT",
          "condition": "NOT EQUALS",
          "sinput": ""
        }
      ],
      "applicability": []
    },
    {
      "external_id": "7419eca0c283da7a150758c925d71b67",
      "name": "5.3.1 — Ensure X-Content-Type-Options header is enabled",
      "description": "The X-Content-Type-Options: nosniff header tells browsers to honour the declared Content-Type rather than guessing.",
      "rational": "MIME sniffing has historically enabled XSS via uploaded files that browsers chose to interpret as HTML.",
      "remediation": "Add `add_header X-Content-Type-Options \"nosniff\" always;`.",
      "severity": "Medium",
      "filter": null,
      "app_filter": null,
      "conditions": [
        {
          "type": "condition",
          "element": "CMD",
          "input": "grep -hiE 'X-Content-Type-Options' /etc/nginx/nginx.conf /etc/nginx/conf.d/*.conf 2>/dev/null | grep -v '^[[:space:]]*#'",
          "selement": "OUTPUT",
          "condition": "NOT EQUALS",
          "sinput": ""
        }
      ],
      "applicability": []
    },
    {
      "external_id": "9f1c105090375c202e019cdda4f44dfa",
      "name": "5.3.2 — Ensure Content Security Policy (CSP) is enabled",
      "description": "CSP restricts which sources of script, style, frames, etc. browsers will honour for the site.",
      "rational": "A well-configured CSP is one of the strongest mitigations against XSS.",
      "remediation": "Add `add_header Content-Security-Policy \"default-src 'self';\" always;` (tune per application).",
      "severity": "Medium",
      "filter": null,
      "app_filter": null,
      "conditions": [
        {
          "type": "condition",
          "element": "CMD",
          "input": "grep -hiE 'Content-Security-Policy' /etc/nginx/nginx.conf /etc/nginx/conf.d/*.conf 2>/dev/null | grep -v '^[[:space:]]*#'",
          "selement": "OUTPUT",
          "condition": "NOT EQUALS",
          "sinput": ""
        }
      ],
      "applicability": []
    },
    {
      "external_id": "ed83caeaf9a936483f0e528b238de1c7",
      "name": "5.3.3 — Ensure the Referrer Policy is configured",
      "description": "The Referrer-Policy header controls how much of the referring URL is sent on outbound navigations.",
      "rational": "Limiting Referer leakage prevents sensitive path parameters and tokens from being exposed to third-party sites.",
      "remediation": "Add `add_header Referrer-Policy \"no-referrer\" always;` or a similarly strict value.",
      "severity": "Medium",
      "filter": null,
      "app_filter": null,
      "conditions": [
        {
          "type": "condition",
          "element": "CMD",
          "input": "grep -hiE 'Referrer-Policy' /etc/nginx/nginx.conf /etc/nginx/conf.d/*.conf 2>/dev/null | grep -v '^[[:space:]]*#'",
          "selement": "OUTPUT",
          "condition": "NOT EQUALS",
          "sinput": ""
        }
      ],
      "applicability": []
    }
  ]
}