# Edge responses and headers

> Status codes the OpenWAF edge answers on its own, the bodies it sends, the headers it adds or removes on responses and the headers your origin receives.

## Status codes

| Status | When | Body |
|---|---|---|
| `301` | Plain HTTP, or `www.<apex>` when the apex is a proxied site. | Redirect to HTTPS or the apex. |
| `301`, `302`, `307`, `308` | A [redirect rule](https://developers.openwaf.dev/rules/redirects/) matched. | Redirect. |
| `400` | Ambiguous `Transfer-Encoding` or conflicting `Content-Length`. | Plain text. |
| `401` | [Access gate](https://developers.openwaf.dev/waf/access-gate/) login page. | HTML form. |
| `403` | IP rule, country rule, threat feed, WAF, SSRF, open redirect or prompt injection shield; AI Crawl Control block (by default). | [Block page](https://developers.openwaf.dev/waf/block-page/). |
| `403` | Challenge or tarpit from AI Crawl Control to a request that isn't a browser navigation. | `{"error":"verificacion de navegador requerida"}` or `{"error":"forbidden"}`. |
| `404` | WordPress hardening, source map or GraphQL shield. | Plain `404 page not found`. |
| `413` | Body larger than `max_body_mb`, or larger than the shields' inspection limit. | Plain text. |
| `421` | The edge doesn't serve this name. | Generic page. |
| `429` | [Rate limiting rule](https://developers.openwaf.dev/waf/rate-limiting/#per-path-rules) with `block` (or `challenge` for non-navigations). | Block page for browsers, `{"error":"rate_limited","retry_after":N}` otherwise, with `Retry-After`. |
| `429` | Rate limit rule, basic rate limit or pagination shield. | Block page. |
| `503` | [Browser challenge](https://developers.openwaf.dev/waf/browser-challenge/). | Proof-of-work page, `Cache-Control: no-store`. |
| `502`, `525`, `526` | The origin couldn't be reached, or its TLS failed. | See [SSL/TLS troubleshooting](https://developers.openwaf.dev/ssl/troubleshooting/). |

AI Crawl Control blocks use the `block_response` you configure (401, 402, 403, 404, 410, 429, 451 or 503); see [AI Crawl Control settings](https://developers.openwaf.dev/ai-crawl-control/settings/#block-response).

## Response headers

On every response from your origin, the edge:

- sets `Server` to `nginx` or your `fake_server_header`;
- removes `X-Powered-By`, `X-AspNet-Version`, `X-AspNetMvc-Version`, `X-Runtime`, `X-Generator`, `X-Debug-Info`, `X-Platform-Server`, `X-Served-By`, `X-Backend-Server`, `X-Drupal-Cache` and `X-Varnish`;
- adds, only when the origin didn't set them: `X-Content-Type-Options: nosniff`, `X-Frame-Options: SAMEORIGIN`, `Referrer-Policy: strict-origin-when-cross-origin` and `Permissions-Policy: camera=(), microphone=(), geolocation=()`;
- sets `Strict-Transport-Security` on HTTPS responses when HSTS is on (see [HSTS](https://developers.openwaf.dev/ssl/hsts/));
- adds `Secure`, `HttpOnly` and `SameSite=Lax` to every `Set-Cookie` that lacks them.

> **Caution: Cookies read by JavaScript**
>
> Because the edge adds `HttpOnly` to cookies that don't have it, scripts can no longer read them with `document.cookie`. Set the attributes you need explicitly at the origin; the edge only adds the ones that are missing.


On `/health`, `/status`, `/version`, `/api/health` and `/api/status`, the edge removes `version`, `build`, `commit`, `node_version`, `framework` and `nestjs` fields from the JSON body, so the stack can't be fingerprinted.

## CORS

If your origin reflects the request's `Origin` in `Access-Control-Allow-Origin`, the edge keeps it only when that origin is the same site (the name itself, a subdomain or a parent) or a host in [`cors_allow_origins`](https://developers.openwaf.dev/waf/settings/#cors-allow-origins). Otherwise it removes `Access-Control-Allow-Origin` and `Access-Control-Allow-Credentials`. A wildcard `*` together with `Access-Control-Allow-Credentials: true` loses the credentials header.

## Headers your origin receives

| Header | Value |
|---|---|
| `X-Forwarded-For`, `X-Real-IP`, `CF-Connecting-IP` | The client IP as the edge sees it (replacing any value the client sent). |
| `X-Forwarded-Host` | The requested host. |
| `X-Forwarded-Proto` | `https` or `http`. |

The edge removes `X-Originating-IP`, `X-Remote-IP`, `X-Remote-Addr`, `X-Client-IP`, `True-Client-IP` and `Forwarded` from requests, so a client can't spoof its address to your application.
