HTTP Security Headers & Content Security Policy
On every response, the Athena web console sends a fixed set of hardening headers — a strict Content-Security-Policy, clickjacking and MIME-sniffing protections, a referrer policy, a browser-feature policy, and (over HTTPS) an HSTS header. This page lists each header, its exact value, and what it means for vulnerability scans, embedding the console, and running behind a reverse proxy.
These headers are built in and applied automatically — there is no setting to turn them on, and they cannot be disabled from the console. This page is a reference so you know exactly what Athena sends (for a security review or penetration test) and how to keep a reverse proxy from stripping or duplicating them.
The headers Athena sends#
Every HTTP response from the console and API carries the following headers. HSTS is the one exception — it is added only over HTTPS in a production deployment (see HSTS).
| Header | Value | What it does |
|---|---|---|
Content-Security-Policy |
default-src 'self'; script-src 'self'; … (see CSP) |
Restricts where scripts, styles, images, fonts, and connections may load from — the primary defense against cross-site scripting (XSS) and content injection. |
X-Frame-Options |
DENY |
Blocks the console from being embedded in an <iframe>, defeating clickjacking. Reinforced by the CSP frame-ancestors 'none' directive. |
X-Content-Type-Options |
nosniff |
Stops browsers from second-guessing (“sniffing”) a response's declared content type, which can turn a benign upload into executable content. |
Referrer-Policy |
strict-origin-when-cross-origin |
Sends the full URL as the referrer only to same-origin destinations; cross-origin requests reveal only the origin, and HTTPS→HTTP downgrades send nothing. |
Permissions-Policy |
camera=(), microphone=(), geolocation=() |
Disables the camera, microphone, and geolocation browser features for the console origin. |
X-XSS-Protection |
1; mode=block |
Enables the legacy reflected-XSS filter in older browsers. Modern browsers rely on the CSP instead; this header is sent for defense in depth. |
Strict-Transport-Security |
max-age=31536000 (365 days) |
Tells browsers to reach the console over HTTPS only. Sent over HTTPS in production. See HSTS. |
Content Security Policy in detail#
The Content-Security-Policy header is the strictest of the set. Its full value is:
default-src 'self';
script-src 'self';
style-src 'self' 'unsafe-inline';
img-src 'self' data:;
font-src 'self';
connect-src 'self' ws: wss:;
frame-ancestors 'none';
report-uri /api/csp-report;
| Directive | Policy | Why |
|---|---|---|
default-src 'self' | Same origin only | The fallback for any resource type not called out below — nothing loads from a third-party origin by default. |
script-src 'self' | Same-origin scripts only | No 'unsafe-inline' and no 'unsafe-eval': injected inline <script> tags and eval()-based payloads are blocked. All console JavaScript is served from the app itself. |
style-src 'self' 'unsafe-inline' | Same-origin plus inline styles | The console emits inline style attributes on components, so inline styles are allowed. Style injection is far lower risk than script injection. |
img-src 'self' data: | Same-origin images and data: URIs | Lets the UI render inline (base64) images alongside images served by the app. |
font-src 'self' | Same-origin fonts only | All fonts are bundled and served locally — nothing is fetched from an external font CDN. |
connect-src 'self' ws: wss: | Same-origin fetch/XHR plus WebSockets | The console uses a live server connection for real-time updates; ws:/wss: permit that WebSocket channel. |
frame-ancestors 'none' | Cannot be framed | The modern equivalent of X-Frame-Options: DENY — the console may not be embedded in any other page. |
report-uri /api/csp-report | Report endpoint | Browsers POST a JSON violation report here whenever the policy blocks something (see CSP violation reports). |
Because script-src, font-src, and default-src are locked
to 'self', Athena never pulls scripts, fonts, or other content from the public
internet at runtime. That is by design for an air-gapped, on-premises deployment — but it also
means a reverse proxy or gateway must not rewrite the console to load assets from an external
origin, or the browser will block them.
HSTS (HTTP Strict Transport Security)#
In a production deployment served over HTTPS, Athena adds a
Strict-Transport-Security header with a one-year max-age
(31536000 seconds). Once a browser sees it, that browser will only ever contact the
console over HTTPS for the next year, even if a user types http:// or clicks a
plaintext link.
- Subdomains are not included — the policy applies only to the exact host the console is reached on, which suits an internal deployment reached by IP or a single hostname.
- Not preloaded — Athena does not submit the host to the browser HSTS preload list, so nothing about your internal hostname is published externally.
HSTS assumes the console presents a trusted certificate. For replacing the built-in self-signed certificate and enforcing TLS 1.2+, see Server TLS Certificate.
CSP violation reports#
The CSP's report-uri points browsers at POST /api/csp-report. Whenever
the policy blocks a resource — a legitimate misconfiguration, or an attempted injection — the
browser sends a small JSON report there. Athena records it to the server log:
- An ordinary violation (for example a blocked inline style during development) is logged at warning level with the violated directive, the document, and the blocked URI.
- A violation whose blocked resource looks like an external script-injection attempt is escalated to a critical log entry with the client IP address, so it stands out in monitoring and in any forwarded log stream.
The endpoint accepts anonymous, unauthenticated POSTs (browsers send reports without
credentials) and always returns a plain 200 OK with no body, so it never leaks
information back to a caller. There is nothing to configure and no UI for it; watch your
server logs — or your
forwarded log stream — to see reports as they arrive.
Behind a reverse proxy#
Athena terminates TLS itself and needs no reverse proxy, but many sites place one in front for TLS offload or a shared virtual IP. When you do, keep these points in mind so the security headers survive the hop:
- Don't strip or override the headers. Athena sets each header on the origin
response. A proxy that rewrites
Content-Security-Policy, dropsX-Frame-Options, or injects a second, weaker copy can silently loosen the console's protections. If your proxy adds its own security headers, make sure it does not duplicate or relax the ones above. - Preserve the WebSocket upgrade. The CSP allows
ws:/wss:because the console keeps a live connection open for real-time updates. A proxy that does not forward WebSocket upgrades will break those updates even though the CSP permits them. - Trust forwarded client information explicitly. Athena honors
X-Forwarded-ForandX-Forwarded-Protoonly from proxies on its trusted-proxy allowlist; otherwise it ignores them and records the proxy's address. This keeps per-IP throttling and the audit trail honest. Configure the allowlist as described in Server TLS Certificate → Behind a reverse proxy usingSecurity:TrustedProxies(individual IPs) and/orSecurity:TrustedProxyNetworks(CIDR subnets).
Vulnerability scans & verification#
A quick way to confirm the headers reach the browser is to request any console URL and inspect the response headers:
# View the security headers on any console response
curl -sI "https://athena.example.com:8443/login"
You should see Content-Security-Policy, X-Frame-Options: DENY,
X-Content-Type-Options: nosniff, Referrer-Policy,
Permissions-Policy, X-XSS-Protection, and — over HTTPS —
Strict-Transport-Security. If a header is missing in the browser but present here,
a proxy or gateway between you and Athena is stripping it.
Security scanners commonly flag style-src 'unsafe-inline' and the presence of
ws: in connect-src. Both are intentional: the console emits inline
style attributes, and it uses a WebSocket channel for live updates. Script execution stays
locked down (script-src 'self', no 'unsafe-eval'), which is where the
real XSS risk lives.