> ## Documentation Index
> Fetch the complete documentation index at: https://docs.37audits.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Server Fingerprint

> Looks for Server, X-Powered-By and X-AspNet-Version headers that reveal the software stack and its version to attackers.

<Info>
  **Security Auditor** — reads the `Server`, `X-Powered-By` and `X-AspNet-Version` response headers of the audited URL and reports the ones that name the software stack, with or without a version number.
</Info>

<CardGroup cols={2}>
  <Card title="Protection" icon="shield-halved">
    Keeps attackers from learning which web server, framework and release run your site straight from its response headers.
  </Card>

  <Card title="Standards" icon="book">
    Follows the `Server` header field of RFC 9110 HTTP Semantics (section 10.2.4), which advises against revealing specific software versions.
  </Card>
</CardGroup>

Web servers and application frameworks like to introduce themselves: `Server: Apache/2.4.41 (Ubuntu)`, `X-Powered-By: PHP/7.4.3`, `X-AspNet-Version: 4.0.30319`. Those headers cost nothing to send and nothing to remove, but they hand an attacker the shortlist of exploits to try. RFC 9110 says a server "ought not" reveal specific software versions through `Server`, because it makes the site "more vulnerable to attacks against software that is known to contain security holes". This auditor reads those three headers from the audited URL and tells you which ones leak a product name or a version.

## How it works

1. **Fetch** — sends a `HEAD` request (or `GET` when `HEAD` is not supported) to the audited URL as 37AuditsBot, without following redirects, so the headers of the audited URL itself are read. A blocked request ends the audit with `590`; a network failure or an HTTP 4xx/5xx answer ends it with `500`. A 3xx answer is still audited.
2. **Read** — collects the `Server`, `X-Powered-By` and `X-AspNet-Version` headers (names matched ignoring case; blank values are ignored; several lines of one header are joined with a comma).
3. **CDN** — when the `Server` value names a known CDN or edge (Cloudflare, CloudFront, Akamai, Imperva, Incapsula), it describes the edge rather than the origin stack, so a CDN `Server` value without a version is not a finding. `X-Powered-By` and `X-AspNet-Version` are evaluated on their own even behind a CDN.
4. **Rules** — one check per header: a value that contains a version number fails (`400`); a value that only names the product warns (`300`, except the CDN `Server` value).
5. **Aggregate** — FAIL wins over WARNING; when no header carries a value, or the only one is a CDN `Server` header, the audit is `SUCCESS` (`200`).
6. **Specification pin** — every run emits `37A-ServerFingerprintAuditor-100` (`INFORMATION`), naming [RFC 9110 HTTP Semantics, section 10.2.4 "Server"](https://www.rfc-editor.org/rfc/rfc9110#section-10.2.4) (June 2022). It does not change the overall status.

## What it audits

Every row maps to one `checkRule*` method and one `CheckCode`, in the order the auditor runs them. CheckCode suffixes use status ranges: `100` information, `200` success, `300–399` warning, `400–499` fail, `500–599` error.

| CheckCode | Status | When it fires | Recommendation | Why it matters |
| - | - | - | - | - |
| <a id="37A-ServerFingerprintAuditor-100" />`37A-ServerFingerprintAuditor-100` | `INFORMATION` | Always. Records the specification this auditor implements (RFC 9110 HTTP Semantics, section 10.2.4 "Server", June 2022). | — (recommendation is `null`; nothing for the site to change) | — |
| <a id="37A-ServerFingerprintAuditor-400" />`37A-ServerFingerprintAuditor-400` | `FAIL` | One check per `Server`, `X-Powered-By` or `X-AspNet-Version` header whose value contains a version number, including a CDN `Server` value such as `cloudflare/1.2.3`. | Remove the `{header}` header from the responses of `{url}`, or at least strip version `{version}` from "`{value}`" so only a product name remains. | A disclosed version lets attackers look up the known vulnerabilities of that exact release and attack them directly, with no guesswork. |
| <a id="37A-ServerFingerprintAuditor-300" />`37A-ServerFingerprintAuditor-300` | `WARNING` | One check per `Server`, `X-Powered-By` or `X-AspNet-Version` header that names the software stack without a version. A `Server` value that names a CDN is exempt; the other headers are not. | Remove the `{header}` header from the responses of `{url}`, or replace "`{value}`" with a neutral value that does not name the product. | Naming the web server or framework tells attackers which product to target, so they can narrow down the exploits to try even before a version is known. |
| <a id="37A-ServerFingerprintAuditor-200" />`37A-ServerFingerprintAuditor-200` | `SUCCESS` | All rules passed: none of the three headers carries a value, or the only one is a `Server` header that names a CDN. The message says which case applies and lists the headers checked. | — | — |
| <a id="37A-ServerFingerprintAuditor-500" />`37A-ServerFingerprintAuditor-500` | `ERROR` | The page could not be fetched (timeout, DNS, TLS) or answered HTTP 4xx/5xx other than a block. | Make sure `{url}` answers with HTTP 2xx or 3xx, then run the audit again. Last error: `{error}`. | — |
| <a id="37A-ServerFingerprintAuditor-590" />`37A-ServerFingerprintAuditor-590` | `ERROR` | The audited page answered HTTP 403, HTTP 429 or a Cloudflare challenge, so 37AuditsBot was blocked before it could read the page. | Allow 37AuditsBot in your firewall or bot protection: allowlist its user agent, or verify its Web Bot Auth signature. See [https://www.37audits.com/bot](https://www.37audits.com/bot). | While 37AuditsBot is blocked this audit cannot look at the site, so problems on it go unreported. |

## Output documentation

| Status | Description | Test logic |
| - | - | - |
| **SUCCESS** | The page does not reveal its software stack | No `Server`, `X-Powered-By` or `X-AspNet-Version` value, or only a CDN `Server` value without a version (`200`). |
| **WARNING** | A header names the product but not its version | At least one header without a version and no header with a version (`300`, one check per header). |
| **FAIL** | A header discloses a software version | At least one header value matches a version number such as `2.4.41`, `10.0` or `8.0.2-dev` (`400`, one check per header). |
| **ERROR** | The auditor could not read the page | Fetch failure or HTTP 4xx/5xx answer (`500`); site blocked 37AuditsBot (`590`). |
| **INFORMATION** | Specification pin | Always emitted (`100`); does not change overall status. |

Each `300` and `400` check carries `header`, `value`, `version` (the matched text, or `null`) and `isCdn` in its `data`; the `200` check carries `checkedHeaders`, `headersFound` and `isCdn`.

## Risks and considerations

### Why fingerprint headers matter

* Vulnerability scanners and attackers match `Server: Apache/2.4.41` or `X-Powered-By: PHP/7.4.3` against public CVE databases in seconds; a version string turns a broad scan into a targeted exploit.
* Even without a version, the product name narrows the attack surface: a site that announces ASP.NET is not probed for WordPress bugs.
* Removing these headers is not a substitute for patching, but it removes the free hint. Keep both the headers quiet and the software current.

### How to fix it

* Apache: `ServerTokens Prod` and `ServerSignature Off`; nginx: `server_tokens off;` (the product name still appears unless a module such as `headers-more` removes the header); IIS / ASP.NET: `<httpRuntime enableVersionHeader="false" />`, remove `X-Powered-By` in `web.config` and `X-AspNet-Version` in `Global.asax`; Express: `app.disable('x-powered-by')` or the `helmet` middleware.
* A CDN or reverse proxy in front of the origin can strip these headers for every application behind it.

### Behavior changes from the previous version of this auditor

* A CDN `Server` value no longer hides the other headers: `Server: cloudflare` with `X-Powered-By: ASP.NET` used to pass and now warns (`300`), because `X-Powered-By` describes the origin, not the edge.
* A page that answers HTTP 4xx or 5xx is reported as `ERROR` (`500`) instead of having its headers audited; the headers of an error page rarely represent the site.
* Unexpected exceptions are no longer turned into an error message by the auditor itself; the platform reports them as "the audit could not finish".

### What this auditor does not check

* Only the audited URL is fetched; other pages, assets or API endpoints may send different headers.
* Redirects are not followed: the headers of the redirect answer are the ones audited.
* Other leaks (`X-Generator`, `Via`, error pages, default favicons, cookie names such as `PHPSESSID`) are out of scope.
* The CDN list is fixed (Cloudflare, CloudFront, Akamai, Imperva, Incapsula); a `Server` value naming another edge, such as `Vercel`, warns like any product name.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.