Check a Site's Security Headers and CSP RAMPART
Paste the response headers from curl or the browser's developer tools and see what they protect against and what they leave open. Nothing is fetched, so it works on pages a scanner cannot reach.
The headers
curl -sSIL https://example.comOr in the browser: developer tools, Network, pick the page, and copy its response headers. Either the raw view or the tidy one will do.
What they protect, and what they leave open
The policy, as a browser reads it
The cookies
Why paste the headers instead of typing an address
A header-scanning website fetches the page from its own servers. That only works for a page on the public internet, and it tells the scanner, and whoever it shares its logs with, which address you were looking at. The pages whose headers matter most are usually the ones it cannot reach: the staging copy before launch, the internal admin panel, the application behind a login, the client's system you are testing under an agreement that says the findings stay private.
Headers are text. The server has already sent them to you. Reading them here means the audit covers exactly the response you have, from wherever you got it, and nothing about the site is sent anywhere.
What it checks, and how carefully
- Content-Security-Policy, the way a browser reads it.
Most mistakes in a policy are silent: a missing semicolon turns the next
directive into a host name,
selfwithout its quotes is a host called self, and a directive written twice keeps only its first copy. Each of those is found rather than trusted. Then the script policy is judged for what it actually lets run: inline script,eval, any host,data:, and hosts where anybody can publish a script or which serve something known to get round an allowlist. A nonce or hash with'strict-dynamic'is recognised as the strong form it is, and'unsafe-inline'beside a nonce is recognised as ignored. - Strict-Transport-Security. Whether it is valid, whether the period is long enough to matter, and whether a site asking for the browsers' preload list would actually be accepted onto it.
- Framing. X-Frame-Options and
frame-ancestorstogether, because the second overrides the first, and becauseALLOW-FROMlooks like protection and is ignored. - Cookies. Secure, HttpOnly and SameSite on each one, the
__Host-and__Secure-prefixes whose rules a browser enforces by quietly dropping the cookie, and a shared cache told it may keep a response that sets one. - Cross-origin reads.
Access-Control-Allow-Origin: null, and the wildcard-with-credentials pair browsers refuse, which tends to get "fixed" by echoing any origin back. - The rest. X-Content-Type-Options, Referrer-Policy, Permissions-Policy, Cross-Origin-Opener-Policy, headers that name the server's software and version, and retired headers that do nothing now.
What one response cannot tell you
Headers are a promise about what the browser should do, not proof the
application is safe. A strong policy on the login page says nothing about the
headers on the API behind it, so check the responses that matter, not only the
home page. Whether a server copies back any Origin it is sent
shows up only by sending it one, and the page says how when it matters. There
is no letter grade here, because a grade adds up things that are not the same
size: a missing header on a static brochure and inline script allowed on a
banking page do not belong on one scale.
For the certificate the site presents, CERTLENS takes it apart. For a token in one of these cookies, JOT reads it. For a copy of the traffic itself, WIRE reads a packet capture and INTERCEPT cleans the secrets out of one before it is shared.
Questions people ask about RAMPART
Why not just use a header scanning website?
Use one if you like, for a public page. It has to fetch the page from its own servers, so it cannot reach a staging site, an intranet application or anything behind a login, and it learns which address you are checking. RAMPART reads headers you already have, so it works on any response and sends nothing anywhere.
How do I get the headers?
From a terminal, curl -sSIL https://the-address prints them, one block for each redirect. In a browser, open the developer tools, go to Network, reload, pick the page and copy its response headers. The raw view and the tidy name-then-value view both work.
Why is 'unsafe-inline' marked as ignored?
When a policy also lists a nonce or a hash, every current browser drops 'unsafe-inline' and runs only the scripts that carry the nonce or match the hash. Leaving it in is the recommended way to keep very old browsers working, so RAMPART counts it as fine in that case and as serious without a nonce or hash.
Why is a CDN in my script-src flagged?
Because trusting a host trusts everything on it. Hosts such as cdn.jsdelivr.net and unpkg.com serve any file anybody publishes to npm or GitHub, and some Google and cdnjs addresses serve old AngularJS or JSONP endpoints that are known ways round an allowlist. Loading the file from your own origin, or moving to nonces with 'strict-dynamic', removes the problem.
Does it give the site a grade?
No. A grade adds together things of very different size: a missing Permissions-Policy on a brochure site and inline script allowed on a payments page are not on one scale. RAMPART sorts what it finds into serious, worth fixing and worth knowing, and says why each one matters and the line that fixes it.
Can it tell whether the server reflects any Origin?
Not from one response. When the headers allow a named origin to read the response, RAMPART says so and gives the curl command that sends a made-up Origin, which is the only way to find out.
Related tools
- CERTLENSTake a certificate or a chain apart and check it
- JOTRead and check a JWT without sending it anywhere
- INTERCEPTClean secrets out of a network log or curl
- COOKIEAUDITSee which cookies are tracking you
- WIRERead a packet capture without uploading it
- FINGERPRINTSee what your browser tells every site you visit