WebPeeks
Headers · CSP · email · robots · meta

Website report card

One graded report for a website's security headers, Content-Security-Policy, email authentication, crawlability and meta tags, with the exact fix for each problem. Paste the response headers to start; the other three inputs are optional. The example below is a small PHP site behind nginx.

Paste what the site sends back

The output of curl -sI for the page. A redirect chain from curl -sIL works too; the last response is graded.
Page <head> 14 lines
View source (Ctrl+U, or Cmd+Option+U on a Mac), copy from <head> to </head>.
robots.txt 16 lines
DNS TXT records 3 lines
dig output as it is, or the bare record text, one record per line.
Updates as you paste. Nothing leaves this page.

Report

74 / 100Overall grade C, 74 out of 100

www.example.com

HTTP/2 200 · 5 of 5 areas checked

2 high11 medium9 notes10 passed

Grade by area
AreaGradeScoreIssues
Security headersC646 medium
Content-Security-PolicyC661 high2 medium
Email authenticationB822 medium
CrawlabilityA100none
Meta and social tagsC671 high1 medium

Security headers

C64 / 100 · weight 30

HTTP/2 200 · 10 headers · open the full security headers tool

  • Medium

    HSTS max-age is 183 days

    Reasonable, but below the one year (31536000) the preload list requires.

    Fix Send HSTS for one year on HTTPS responses. Add includeSubDomains only once every subdomain serves HTTPS.

    Show nginx · Apache · Cloudflare
    nginx
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
    Apache
    Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
    Cloudflare
    SSL/TLS > Edge Certificates > HTTP Strict Transport Security (HSTS)
    Enable, Max Age 12 months, include subdomains if every subdomain is HTTPS
  • Medium

    Referrer-Policy is not set

    Current Chrome, Firefox and Safari default to strict-origin-when-cross-origin, which is sensible. Setting it explicitly makes the behaviour the same in every browser.

    Fix Send only the origin to other sites, never the full URL.

    Show nginx · Apache · Cloudflare
    nginx
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;
    Apache
    Header always set Referrer-Policy "strict-origin-when-cross-origin"
    Cloudflare
    Rules > Transform Rules > Modify Response Header
    Set static  Referrer-Policy
    Value       strict-origin-when-cross-origin
  • Medium

    Permissions-Policy is missing

    Optional, but a short policy such as camera=(), microphone=(), geolocation=() stops embedded third-party content from asking for those permissions.

    Fix Switch off browser features the site does not use. List any feature you do use as, for example, geolocation=(self).

    Show nginx · Apache · Cloudflare
    nginx
    add_header Permissions-Policy "camera=(), microphone=(), geolocation=(), payment=()" always;
    Apache
    Header always set Permissions-Policy "camera=(), microphone=(), geolocation=(), payment=()"
    Cloudflare
    Rules > Transform Rules > Modify Response Header
    Set static  Permissions-Policy
    Value       camera=(), microphone=(), geolocation=(), payment=()
  • Medium

    Server header reveals a version: nginx/1.24.0

    A version number tells an attacker which known vulnerabilities to try. Most servers can be told to omit it (nginx: server_tokens off).

    Fix Hide the version number.

    Show nginx · Apache · Cloudflare
    nginx
    server_tokens off;   # in the http block
    Apache
    ServerTokens Prod
    ServerSignature Off
    Cloudflare
    Rules > Transform Rules > Modify Response Header
    Remove  Server
  • Medium

    x-powered-by: PHP/8.2.12

    Advertises the software stack for no benefit to visitors. Remove it.

    Fix Stop advertising the application stack. For PHP, expose_php = Off in php.ini removes it at the source.

    Show nginx · Apache · Cloudflare
    nginx
    fastcgi_hide_header X-Powered-By;   # PHP-FPM
    proxy_hide_header X-Powered-By;     # reverse proxy
    Apache
    Header always unset X-Powered-By
    Cloudflare
    Rules > Transform Rules > Modify Response Header
    Remove  X-Powered-By
  • Medium

    Cookie session lacks Secure, SameSite

    Secure keeps it off plain HTTP; HttpOnly hides it from JavaScript (omit only if scripts must read it); SameSite limits cross-site sending (Chromium defaults to Lax when absent).

    Fix Set the missing attributes where the cookie is created. The server-level lines add them to every cookie the backend sets.

    Show App · nginx · Apache
    App
    Set-Cookie: session=...; Path=/; Secure; HttpOnly; SameSite=Lax
    nginx
    proxy_cookie_flags ~ secure httponly samesite=lax;   # nginx 1.19.3+
    Apache
    Header always edit Set-Cookie ^(.*)$ "$1; Secure; HttpOnly; SameSite=Lax"
2 checks passed
  • Pass

    X-Frame-Options: SAMEORIGIN

    Other sites cannot put this page in a frame, which prevents clickjacking.

  • Pass

    X-Content-Type-Options: nosniff

    Browsers will not guess a different content type than the one declared, which stops some upload-based attacks.

Content-Security-Policy

C66 / 100 · weight 20

Content-Security-Policy header · 3 directives · open the full content-security-policy tool

  • High

    script-src: 'unsafe-inline' allows inline script

    Any injected <script> block or onclick= attribute runs, which is exactly what CSP exists to prevent. Replace it with nonces or hashes.

    Fix Give each inline script a per-response nonce and drop 'unsafe-inline'. The application has to generate the nonce; a static web server cannot.

    Show CSP · HTML
    CSP
    script-src 'nonce-{random per response}' 'strict-dynamic';
    HTML
    <script nonce="{same random value}">...</script>
  • Medium

    object-src is 'self' (from default-src)

    Recommended value is 'none'. It costs nothing on a modern site.

    Fix Add object-src 'none'. Nothing on a current site needs <object> or <embed>.

    Show CSP
    CSP
    object-src 'none';
  • Medium

    No base-uri

    base-uri does not fall back to default-src. Without it, an injected <base href> tag can redirect every relative script URL on the page to an attacker's host, bypassing nonce-based policies. Set base-uri 'none' or 'self'.

    Fix Add base-uri 'self' (or 'none' if the site has no <base> tag).

    Show CSP
    CSP
    base-uri 'self';
  • Note

    script-src: host allowlist (1 host)

    Allowlists are often bypassable: if any listed host serves JSONP endpoints, user uploads or an old copy of AngularJS, an attacker can run script from it. Nonces with 'strict-dynamic' avoid the problem.

  • Note

    No frame-ancestors

    Other sites may embed this page in a frame (clickjacking risk) unless X-Frame-Options is set. frame-ancestors 'self' or 'none' is the modern replacement for X-Frame-Options.

    Fix Add frame-ancestors 'self' to control who can frame the page.

    Show CSP
    CSP
    frame-ancestors 'self';
  • Note

    No form-action

    form-action does not fall back to default-src, so an injected form could post to any host. form-action 'self' is a cheap addition if all forms submit to your own site.

    Fix Add form-action 'self' if every form on the site submits to the site itself.

    Show CSP
    CSP
    form-action 'self';
  • Note

    No reporting endpoint

    Without report-uri or report-to you will not hear about violations, including ones that break your own pages.

    Fix Add a report-uri (or report-to) endpoint to hear about violations. Any URL that accepts a POST will do; report collection services give you one.

    Show CSP
    CSP
    report-uri /csp-report;

Email authentication

B82 / 100 · weight 20

3 TXT records: SPF, DMARC, DKIM · open the full email authentication tool

  • Medium

    DMARC: p=none: monitoring only

    Mail that fails DMARC is still delivered normally. That is the right first step while you read reports; move to quarantine, then reject, once legitimate senders all pass. Google and Yahoo require at least p=none from bulk senders.

    Fix Once the reports show every legitimate sender passing, move to quarantine, then reject.

    Show DNS
    DNS
    _dmarc.example.com.  TXT  "v=DMARC1; p=quarantine; rua=mailto:dmarc-reports@example.com"
  • Medium

    DKIM: RSA key of 1024 bits

    1024-bit keys still verify, but RFC 8301 recommends 2048 bits for signers, and 1024-bit RSA is within reach of well-funded attackers. Rotate to 2048.

    Fix Generate a 2048-bit key under a new selector in your mail provider's settings, publish it, switch signing to it, then retire the old selector.

  • Note

    SPF: 2 DNS-querying terms at the top level

    Each include: pulls in another record whose own lookups count toward the same limit of 10, and this tool cannot see inside them. Check the total with the record of each included domain.

2 checks passed
  • Pass

    SPF: ~all (softfail)

    Unlisted senders softfail: most receivers accept but mark or score the message. With DMARC in place, many operators keep ~all deliberately and let DMARC decide.

  • Pass

    DMARC: Aggregate reports go to 1 address

    If a report address is on a different domain, that domain must publish an authorisation record (RFC 7489 7.1), which report services set up for you.

Crawlability

A100 / 100 · weight 15

robots.txt · 3 groups · open the full crawlability tool

  • Note

    Blocks GPTBot

    These are AI crawlers, not search engines, so blocking them does not affect search ranking. It is a choice, not an error.

  • Note

    Line 15: crawl-delay: 10

    Not part of RFC 9309. Bing and Yandex honour it; Google ignores it.

2 checks passed
  • Pass

    Googlebot and Bingbot may crawl the homepage

    Tested against the path / with the RFC 9309 matching rules.

  • Pass

    Sitemap listed (1)

    https://www.example.com/sitemap.xml

Meta and social tags

C67 / 100 · weight 15

10 meta tags, 1 link tags · open the full meta and social tags tool

  • High

    og:image is not an absolute URL

    "/images/share-card.jpg" — crawlers fetch the image directly and do not resolve relative paths. Use the full https:// URL.

    Fix Use the image's full https:// URL.

    Show HTML
    HTML
    <meta property="og:image" content="https://www.example.com/share-card.png">
  • Medium

    Title is 86 characters

    Google cuts titles by pixel width (about 600px), which is typically 50–60 characters; the rest becomes "…". Put the words that matter first.

    Fix Shorten the title to about 60 characters and put the important words first.

  • Note

    No og:image:width / og:image:height

    Optional, but declaring them lets some platforms render the card on the first share instead of after fetching the image.

  • Note

    No og:image:alt

    Alt text for the preview image, read by screen readers on platforms that support it.

4 checks passed
  • Pass

    Description is 109 characters

  • Pass

    Canonical URL set

    https://www.example.com/coffee/

  • Pass

    Required Open Graph tags present

    og:title, og:type, og:image and og:url.

  • Pass

    twitter:card is summary_large_image

Method · last reviewed

What the report checks

Each area runs the same code as one of the single-purpose tools on this site, so a finding here reads exactly as it does there. Open the tool for the full detail of one area.

AreaReadsWeightStandard
Security headersHSTS, framing, nosniff, Referrer-Policy, Permissions-Policy, cookies, version leaks30RFC 6797, Fetch, RFC 6265
Content-Security-PolicyThe CSP header, a report-only header, or a <meta http-equiv> policy20W3C CSP Level 3
Email authenticationSPF, DMARC and DKIM TXT records20RFC 7208, 7489, 6376, 8301
Crawlabilityrobots.txt against Googlebot and Bingbot on the homepage, Sitemap lines, X-Robots-Tag15RFC 9309
Meta and social tagsTitle, description, canonical, robots meta, viewport, Open Graph, X card15ogp.me, Google Search Central

How the grade is worked out

Every area is scored out of 100. The overall score is the weighted average of the areas you gave it input for; an area left empty is marked "not checked" and its weight is shared among the rest. The letter is the same scale as the headers checker: A from 90, B from 75, C from 60, D from 40, F below.

These weights are this site's judgement of how much each area matters to an ordinary website, not an industry standard. Two sites with the same grade can have very different problems, which is why the findings list matters more than the letter.

Reading the fixes

Configuration fixes come as three snippets. nginx lines go in the server block; the always keyword makes nginx add the header to error pages and redirects too. Apache lines go in the virtual host or .htaccess and need mod_headers. Cloudflare lines describe where to set the header in the dashboard (a Transform Rule), which is the route when the origin server is not yours to change. DNS fixes show the record to publish, and page fixes show the tag. Adapt the placeholders in angle brackets.

After a change, run the same command again and paste the new output. If a header you added does not appear, something in front of the server (a CDN, a proxy, a hosting control panel) may be replacing the headers, or nginx may be ignoring it because a location block has its own add_header lines, which replace rather than add to the ones in the server block.

What to fix first

  1. Anything that hides the site: Disallow: / for every crawler, or a noindex header or tag on a live page.
  2. Missing SPF or DMARC. Without them anyone can send mail that claims to be from your domain, and large mailbox providers increasingly reject or junk mail from domains without DMARC.
  3. The one-line headers: HSTS, X-Content-Type-Options: nosniff, framing protection and Referrer-Policy.
  4. The Content-Security-Policy. It protects the most and takes the most care: deploy it as Content-Security-Policy-Report-Only, read the reports, then enforce it.
  5. Meta and social tags, which change how the site looks in search results and shared links.

Where this report stops being reliable

Common questions

Why can I not just enter my URL?

A web page is not allowed to read another site's response headers: the browser's same-origin and CORS rules block it, and WebPeeks deliberately has no server to fetch sites on your behalf. So you run one command (curl -sI https://your-site/) and paste the output. Nothing you paste is sent anywhere, which also means you can check a staging site, an internal host or a change you have not deployed yet.

How is this different from a security headers scanner?

Header scanners grade one thing: the response headers. This report adds the three other things that usually go wrong on a small site: email authentication (SPF, DMARC, DKIM), crawlability (robots.txt and X-Robots-Tag), and the meta and social tags. It also reads each value rather than only checking that a header exists, and gives the configuration line to fix each finding.

Does an A mean my website is secure?

No. The report checks configuration you can see from outside: headers, DNS records and page tags. A site with an A can still have a vulnerable plugin, a weak admin password or an injectable form. What an A does say is that the protections that cost almost nothing to switch on are switched on.

What should I fix first?

Anything that stops the site being found or trusted: a Disallow: / or noindex on a live site, a missing SPF or DMARC record, or a missing HSTS or X-Content-Type-Options header. Those are one-line changes. A Content-Security-Policy without 'unsafe-inline' is worth more but takes longer, because inline scripts need nonces; start it as report-only.

Do I have to paste all four inputs?

Only the headers are required. Each optional input adds an area to the report; an area you leave empty is marked "not checked" and does not count toward the overall grade, so leaving out the DNS records does not lower the score.

Does blocking AI crawlers in robots.txt lower the grade?

No. GPTBot, ClaudeBot, CCBot and Google-Extended are not search engine crawlers, so blocking them does not affect search results. The report notes the block and does not deduct for it. Blocking Googlebot or Bingbot from the homepage does cost points.

How do I share the report?

Use "Copy as Markdown" above the report. It copies the overall grade, the grade per area and the list of things to fix, with the first configuration line for each, as Markdown that pastes cleanly into a ticket, a pull request or a chat message. The report is not stored anywhere, so there is no link to share.