# HTTP TRACE Method: What It Does and Why to Disable It

> HTTP TRACE echoes the request back for diagnostics. Cross-Site Tracing history, why scanners flag "TRACE enabled", and how to disable it in Apache and nginx.

Source: https://howhttpworks.com/methods/trace
Last reviewed: 2026-10-04

> **TL;DR:** TRACE makes a server echo your request back as `message/http`, a diagnostic from the 1990s. Browsers forbid it in `fetch` and `XMLHttpRequest`, but scanners still flag servers that answer it, so turn it off: `TraceEnable off` in Apache, and make sure nginx or your backend returns 405.

## What it does

A TRACE request carries no body. The server (or the last proxy, when `Max-Forwards` runs down to 0) replies `200` and puts the request it received in the body. [RFC 9110 section 9.3.8](https://www.rfc-editor.org/rfc/rfc9110#section-9.3.8) specifies it:

```http
TRACE /hello HTTP/1.1
Host: example.com
Max-Forwards: 2
```

```http
HTTP/1.1 200 OK
Content-Type: message/http

TRACE /hello HTTP/1.1
Host: example.com
Max-Forwards: 1
Via: 1.1 edge-proxy
```

The point was to see how intermediaries changed the request: a proxy that added a `Via` header or decremented `Max-Forwards` shows up in the echo. The RFC says a client must not send content or sensitive fields such as cookies or credentials in a TRACE request, and that a server should not reflect fields that could hold sensitive data. Nobody uses it for diagnostics now; `curl -v`, [Via](https://howhttpworks.com/headers/via) and proxy logs do the job.

## Cross-Site Tracing and why it is still flagged

In 2003 Jeremiah Grossman published a white paper on Cross-Site Tracing (XST). The trick: an XSS payload sends a TRACE request to the victim site. The browser attaches its cookies (and any cached HTTP credentials) automatically, the server echoes them back in the body, and the script reads the body. That defeated `HttpOnly`, which only hides cookies from `document.cookie`, not from an echoed response.

Browsers closed the browser-side path by refusing to send TRACE from script. The Fetch Standard lists `CONNECT`, `TRACE` and `TRACK` as forbidden methods, so `fetch('/', { method: 'TRACE' })` rejects with a `TypeError` before anything goes on the network. XST as originally described is therefore not practical against current browsers, and the finding is usually rated low severity.

Scanners (Nessus, Qualys, OWASP ZAP, PCI ASV tooling) still report "HTTP TRACE method enabled" because the check is cheap and the remedy is trivial. Treat it as hygiene: it removes a finding and an echo endpoint that can leak headers added by proxies or gateways, such as internal forwarding or authentication headers.

## Check whether it is enabled

```bash
curl -i -X TRACE https://example.com/
```

A server that supports it returns `200 OK` with `Content-Type: message/http`. A hardened one returns `405`, `403` or `501`. Test the public hostname, not only the origin, because a CDN or load balancer in front can answer differently from the server behind it.

## Disable it

Apache has a dedicated directive, and it defaults to on:

```apache
TraceEnable off
```

With that set, Apache answers TRACE with `405 Method Not Allowed` (checked on httpd 2.4). The directive is valid in server config and virtual host context, not `.htaccess`. `TraceEnable extended` goes the other way and allows a request body, for conformance testing.

nginx has no TRACE feature to switch off. Serving its own content, stock nginx replies `405 Not Allowed` to TRACE (tested on the official `nginx:alpine` image). When you `proxy_pass`, nginx forwards the method upstream, so a backend that echoes TRACE is reachable through it. Block unwanted methods at the edge:

```nginx
server {
    # Allow only the methods this site uses
    if ($request_method !~ ^(GET|HEAD|POST|PUT|PATCH|DELETE|OPTIONS)$) {
        return 405;
    }
}
```

Tomcat disables it by default: the `allowTrace` attribute on `<Connector>` defaults to `false`.

## Related

TRACE is safe and idempotent in RFC 9110 terms but not cacheable. If your scan also lists unexpected `OPTIONS` or `PUT`, see [OPTIONS](https://howhttpworks.com/methods/options); a rejected method comes back as [405](https://howhttpworks.com/status-codes/405) or [501](https://howhttpworks.com/status-codes/501).
