Web Server audit fixes

Identification & Patching: fixing all 5 checks

Identification and patching inventories the web servers on the host, what their Server header gives away, which user the workers run as, and how far behind nginx, Apache and OpenSSL are on patches.

Two of the skips describe the run rather than the host: Config Syntax skips whenever the audit cannot become root, because nginx -t and apachectl configtest need it, and Web Server Updates skips when no apt, dnf, yum, zypper or apk is present. Worker Process User skips separately when the server is installed but stopped and the nginx config names no user, since there is then no process to read a uid from.

5
checks in this audit
2
rated high severity
1
need root or sudo
~9s
automated run time

Transcribed from the web-server-security-identification-patching audit script.

Every check

Find your finding

Listed in the order the audit runs them. Take the check name from the third field of the result line and open its page.

  • Web Server Inventory

    Soon

    Detects which web servers are installed and running, and reports their versions

    LowNo root2 results
  • Version Disclosure

    Soon

    Checks whether the Server header leaks an exact version and whether server_tokens/ServerTokens suppression is set

    LowNo root3 results
  • Worker Process User

    Soon

    Checks whether web server worker processes run as root or as a dedicated unprivileged user

    HighNo root3 results
  • Web Server Updates

    Soon

    Checks for pending package and security updates across the web stack, including OpenSSL

    HighNo root4 results
  • Web Server Config Syntax

    Soon

    Runs the web server config test to confirm the config on disk will reload cleanly

    MediumNeeds root3 results
Shared script behaviour

How the Identification & Patching audit reads your server

Every check in this audit runs after the same preamble, and several of its results only make sense once you know what that preamble could and could not see.

All web-server scripts share one preamble. It detects nginx, Apache (apache2/httpd, APROOT = /etc/apache2 or /etc/httpd), Caddy and lighttpd. NGT is nginx -T output (effective config with every include expanded) when root, otherwise a concatenation of nginx.conf, conf.d/*.conf, sites-enabled/*. APC is the concatenated Apache config tree (main file, ports.conf, conf.d, conf-enabled, sites-enabled, mods-enabled, conf.modules.d), comments stripped; APM is apachectl -M (root) or the mods-enabled/*.load names. WROOTS are all root/DocumentRoot values. A live probe curls https://127.0.0.1/, http://127.0.0.1/, http://127.0.0.1:8080/ with the first real server_name/ServerName as Host:. hdr NAME reads a response header; code URL returns the HTTP status. Caddy and lighttpd are detected but their configs are not parsed, so most checks on those hosts rely on the live probe only. Messages ending in "(no live response, config only)" or "(default vhost only - no server_name found to probe)" mean the probe could not be used.

Why checks skip

A SKIP is never a pass

A skipped check verified nothing at all. The most common cause is privilege: 1 of the 5 checks in this audit need root for a complete result. Before every run, each script works out which of four privilege modes it is in.

The four privilege modes an audit script can run in, and what each one means for checks that need root
ModeHow it is reachedWhat it means for your results
rootThe audit runs as UID 0.Every privileged branch runs directly. No check skips for lack of permission.
nopasssudo -n true succeeds, so the account has passwordless sudo.Privileged commands run through sudo -n.
passA sudo password was supplied in the CtrlOps audit settings and accepted.Privileged commands run through sudo -S.
noneNone of the above worked.CAN_ROOT=0. Every privileged branch returns SKIP with a "Need root" message rather than guessing.

If many checks skip with a “need root” message, run the audit as root, grant the audit account sudo (with or without NOPASSWD), or supply the sudo password in the CtrlOps audit settings.

FAQ

Identification & Patching questions

Yes, as long as it carries no version number. The check warns only when the live Server header matches a version pattern such as 1.24.0; a bare nginx or Apache is a PASS, which is as far as server_tokens off and ServerTokens Prod can take you without a third-party module. Watch the other branch instead: with no live response it falls back to the config, and finding suppression configured there gives a PASS that was never confirmed against a real response.
No. It filters the pending update list for nginx, apache2, httpd, openssl and libssl only, so PHP, your application runtime and the rest of the OS are out of scope; the Linux server System Updates audit covers those. It reads cached package metadata, so a stale apt update gives a stale answer, and only the apt branch can identify a security update and FAIL. On dnf, yum, zypper and apk every pending update comes back as a WARN.
Do not restart it. The FAIL means the config on disk no longer passes its own test while the running process is still serving from the config it loaded earlier, so a restart would take the site down and a reload would be rejected. Run nginx -t or apachectl configtest yourself for the file and line, fix it, repeat until the test is clean, then reload. Note that this check skips entirely without root, so a skip is not evidence that the config is valid.
Audit your fleet

Run all 5 Identification & Patching checks, in one click

CtrlOps runs this audit over your existing SSH connection - no agents, no scripts to manage. $7/user/month after a 1 month free trial - no credit card required.

Start instantly· No credit card· No sneaky autorenewals