<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Guardr</title>
    <description>The latest articles on DEV Community by Guardr (@guardr).</description>
    <link>https://dev.to/guardr</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3818937%2F745985b4-6d7d-43e9-b358-a5029120aeb4.png</url>
      <title>DEV Community: Guardr</title>
      <link>https://dev.to/guardr</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/guardr"/>
    <language>en</language>
    <item>
      <title>SecurityHeaders.com API Is Gone — Here's the Migration</title>
      <dc:creator>Guardr</dc:creator>
      <pubDate>Fri, 24 Apr 2026 15:03:08 +0000</pubDate>
      <link>https://dev.to/guardr/securityheaderscom-api-is-gone-heres-the-migration-4461</link>
      <guid>https://dev.to/guardr/securityheaderscom-api-is-gone-heres-the-migration-4461</guid>
      <description>&lt;p&gt;If you have CI/CD pipelines or scheduled audits built on &lt;code&gt;api.securityheaders.com&lt;/code&gt;, now is the time to migrate — the API has been discontinued and no new or renewed subscriptions are being issued. Better to move before your key stops working than after.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The SecurityHeaders.com API has been discontinued&lt;/strong&gt; — no new subscriptions, no renewals. The free web UI at securityheaders.com is still live, but if your existing key expires you have nowhere to go. This post is a practical migration guide with real before/after curl examples and a working GitHub Actions workflow.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why developers used it in the first place
&lt;/h2&gt;

&lt;p&gt;HTTP security headers — things like &lt;code&gt;Content-Security-Policy&lt;/code&gt;, &lt;code&gt;Strict-Transport-Security&lt;/code&gt;, &lt;code&gt;X-Frame-Options&lt;/code&gt; and &lt;code&gt;Permissions-Policy&lt;/code&gt; — are one of the easiest ways to harden a website against a whole class of attacks: XSS, clickjacking, protocol downgrade, MIME sniffing and more. Browsers respect them natively, no client-side code required.&lt;/p&gt;

&lt;p&gt;The problem is that getting them right is tedious. Each header has its own syntax, edge cases and gotchas. Miss one, misconfigure another, and your security posture quietly regresses with no visible symptoms.&lt;/p&gt;

&lt;p&gt;SecurityHeaders.com solved this with a simple letter grade. Paste a URL, get an A–F score and a list of what's missing or misconfigured. The API took that same scan and made it programmable — so developers could:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Gate CI/CD pipelines&lt;/strong&gt; — fail the build if headers regress before a deploy goes live&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Run scheduled audits&lt;/strong&gt; across dozens of domains and feed results into a dashboard or Slack alert&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Generate compliance evidence&lt;/strong&gt; for SOC 2, PCI or internal security reviews&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Power client reports&lt;/strong&gt; for agencies managing security across multiple sites&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If any of those sound useful, read on — this guide covers how to replicate them with the Guardr API.&lt;/p&gt;




&lt;h2&gt;
  
  
  Quick recap: what happened
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;January 2023&lt;/strong&gt; — SecurityHeaders.com launched a paid API&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;June 2023&lt;/strong&gt; — Probely acquired SecurityHeaders.com from its creator Scott Helme&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;June 2025&lt;/strong&gt; — Snyk acquired Probely&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;April 2025&lt;/strong&gt; — Probely announced the API would be retired in April 2026, giving a full year's notice&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;April 2026&lt;/strong&gt; — API discontinued, no new or renewed subscriptions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Credit to Scott Helme and the Probely/Snyk team for the generous notice window. The web scanner at securityheaders.com is a genuine contribution to web security and it continues to exist. This is just about replacing the programmatic endpoint.&lt;/p&gt;




&lt;h2&gt;
  
  
  The migration in one swap
&lt;/h2&gt;

&lt;p&gt;The most common use case was a single GET per domain returning a grade. Here's the before/after:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Before (SecurityHeaders.com):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"x-api-key: YOUR_OLD_KEY"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s2"&gt;"https://api.securityheaders.com/?q=example.com&amp;amp;hide=on&amp;amp;followRedirects=on"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;After (&lt;a href="https://guardr.io/docs/api" rel="noopener noreferrer"&gt;Guardr API&lt;/a&gt;):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-API-Key: YOUR_NEW_KEY"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s2"&gt;"https://api.guardr.io/v1/scan/example.com"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Same auth header style, same GET-per-domain pattern. The &lt;code&gt;hide&lt;/code&gt; and &lt;code&gt;followRedirects&lt;/code&gt; params don't have equivalents — results are private to your account by default and redirects are always followed.&lt;/p&gt;

&lt;p&gt;Want to try it without signing up? The GET endpoint works keyless at 20 req/day per IP, returning grade + score only:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl https://api.guardr.io/v1/scan/example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  What the response looks like
&lt;/h2&gt;

&lt;p&gt;Here's a real response from a domain with issues (trimmed but every field name is exact):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"domain"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"example.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scanned_at"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-04-18T12:46:48.373Z"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"grade"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"C-"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"score"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;58&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"categories"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"tls"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;55&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"headers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"cookies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"dns"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;90&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"exposure"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"issues"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"HSTS not enabled"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"severity"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"high"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"category"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"TLS"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Strict-Transport-Security header is missing..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"remediation"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"effort"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"moderate"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"warning"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Before enabling HSTS, make sure your entire site works over HTTPS — including all subdomains if using includeSubDomains."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"snippets"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"platform"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Cloudflare (_headers)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/*&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  Strict-Transport-Security: max-age=31536000; includeSubDomains; preload"&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"platform"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Nginx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"add_header Strict-Transport-Security &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;max-age=31536000; includeSubDomains; preload&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt; always;"&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"total_issues"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"issues_truncated"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A few things worth calling out for developers:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;remediation.effort&lt;/code&gt;&lt;/strong&gt; tags every issue as &lt;code&gt;quick-fix&lt;/code&gt;, &lt;code&gt;moderate&lt;/code&gt;, or &lt;code&gt;requires-planning&lt;/code&gt;. Useful for sprint planning — you can filter for quick wins before tackling CSP rollouts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;remediation.warning&lt;/code&gt;&lt;/strong&gt; surfaces the gotchas inline. HSTS warns you about subdomain rollout. CSP warns about third-party integrations breaking. These are the notes that usually live in a senior engineer's head.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;remediation.snippets&lt;/code&gt;&lt;/strong&gt; is an array of platform-specific config code — Cloudflare &lt;code&gt;_headers&lt;/code&gt; format, Nginx &lt;code&gt;add_header&lt;/code&gt;, Apache &lt;code&gt;Header always set&lt;/code&gt;. No translating from generic advice.&lt;/p&gt;




&lt;h2&gt;
  
  
  Field mapping from the old API
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;What you want&lt;/th&gt;
&lt;th&gt;SecurityHeaders.com&lt;/th&gt;
&lt;th&gt;Guardr&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Letter grade&lt;/td&gt;
&lt;td&gt;&lt;code&gt;summary.grade&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;grade&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Numeric score&lt;/td&gt;
&lt;td&gt;not available&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;score&lt;/code&gt; (0–100)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Timestamp&lt;/td&gt;
&lt;td&gt;&lt;code&gt;summary.timestamp&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;scanned_at&lt;/code&gt; (ISO 8601)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Header findings&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;summary.headers&lt;/code&gt; (traffic-light)&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;issues[]&lt;/code&gt; with severity + remediation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Raw response headers&lt;/td&gt;
&lt;td&gt;&lt;code&gt;rawHeaders[]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;not returned (use HEAD request if needed)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Grade cap explanation&lt;/td&gt;
&lt;td&gt;&lt;code&gt;summary.gradeCap&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;categories&lt;/code&gt; object&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The key conceptual shift: the old API was &lt;strong&gt;header-centric&lt;/strong&gt; (organized around raw HTTP headers). Guardr is &lt;strong&gt;issue-centric&lt;/strong&gt; (organized around "what's wrong and how to fix it"). Better for CI/CD gating; less useful if you specifically wanted a raw header dump.&lt;/p&gt;




&lt;h2&gt;
  
  
  GitHub Actions workflow
&lt;/h2&gt;

&lt;p&gt;Here's a migrated version of the most common CI pattern — nightly scan with grade-based fail:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# .github/workflows/security-scan.yml&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Security Header Scan&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;schedule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;cron&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;4&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*'&lt;/span&gt;
  &lt;span class="na"&gt;workflow_dispatch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;scan&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Scan site with Guardr&lt;/span&gt;
        &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;GUARDR_API_KEY&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.GUARDR_API_KEY }}&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;response=$(curl -sf \&lt;/span&gt;
            &lt;span class="s"&gt;-H "X-API-Key: $GUARDR_API_KEY" \&lt;/span&gt;
            &lt;span class="s"&gt;"https://api.guardr.io/v1/scan/example.com")&lt;/span&gt;

          &lt;span class="s"&gt;grade=$(echo "$response" | jq -r '.grade')&lt;/span&gt;
          &lt;span class="s"&gt;score=$(echo "$response" | jq -r '.score')&lt;/span&gt;
          &lt;span class="s"&gt;headers_score=$(echo "$response" | jq -r '.categories.headers')&lt;/span&gt;

          &lt;span class="s"&gt;echo "Grade: $grade | Score: $score | Headers: $headers_score"&lt;/span&gt;

          &lt;span class="s"&gt;if [[ "$grade" == "D" || "$grade" == "E" || "$grade" == "F" \&lt;/span&gt;
                &lt;span class="s"&gt;|| "$grade" == "C" || "$grade" == "C-" ]]; then&lt;/span&gt;
            &lt;span class="s"&gt;echo "::error::Security grade regressed to $grade"&lt;/span&gt;
            &lt;span class="s"&gt;echo "$response" | jq '.issues[] | select(.severity == "critical" or .severity == "high")'&lt;/span&gt;
            &lt;span class="s"&gt;exit 1&lt;/span&gt;
          &lt;span class="s"&gt;fi&lt;/span&gt;

          &lt;span class="s"&gt;if (( headers_score &amp;lt; 70 )); then&lt;/span&gt;
            &lt;span class="s"&gt;echo "::error::Headers score dropped to $headers_score"&lt;/span&gt;
            &lt;span class="s"&gt;exit 1&lt;/span&gt;
          &lt;span class="s"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add &lt;code&gt;GUARDR_API_KEY&lt;/code&gt; to your repo secrets and generate the key in the Guardr dashboard under &lt;strong&gt;Settings → API Access&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  What about forcing a fresh scan?
&lt;/h2&gt;

&lt;p&gt;The GET endpoint returns a cached result (up to an hour old). For CI runs where you want a live scan, use the POST endpoint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="s2"&gt;"https://api.guardr.io/v1/scan"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-API-Key: YOUR_NEW_KEY"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"domain":"example.com"}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;POST scans complete in 5–15 seconds. Note the per-domain scan quota — on Free that's once every 7 days, on Solo once every 24 hours. For large sweeps, trigger one POST per domain then use GET for all subsequent reads.&lt;/p&gt;




&lt;h2&gt;
  
  
  Rate limits
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Plan&lt;/th&gt;
&lt;th&gt;Burst limit&lt;/th&gt;
&lt;th&gt;Scan window&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Public (no key)&lt;/td&gt;
&lt;td&gt;20 req/day per IP&lt;/td&gt;
&lt;td&gt;read only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;td&gt;5 req/min&lt;/td&gt;
&lt;td&gt;1 scan/domain/7 days&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Solo ($7/mo)&lt;/td&gt;
&lt;td&gt;15 req/min&lt;/td&gt;
&lt;td&gt;1 scan/domain/24 hrs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Starter&lt;/td&gt;
&lt;td&gt;30 req/min&lt;/td&gt;
&lt;td&gt;1 scan/domain/24 hrs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pro&lt;/td&gt;
&lt;td&gt;60 req/min&lt;/td&gt;
&lt;td&gt;1 scan/domain/6 hrs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Agency&lt;/td&gt;
&lt;td&gt;120 req/min&lt;/td&gt;
&lt;td&gt;1 scan/domain/1 hr&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Every response includes &lt;code&gt;X-RateLimit-Limit&lt;/code&gt;, &lt;code&gt;X-RateLimit-Remaining&lt;/code&gt;, &lt;code&gt;X-RateLimit-Reset&lt;/code&gt; and &lt;code&gt;Retry-After&lt;/code&gt; on 429s. Respect &lt;code&gt;Retry-After&lt;/code&gt; — don't hammer on rate limit errors.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Guardr covers that the old API didn't
&lt;/h2&gt;

&lt;p&gt;Beyond security headers, a Guardr scan also checks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;TLS&lt;/strong&gt; — HSTS presence and config (&lt;code&gt;hstsMaxAge&lt;/code&gt;, &lt;code&gt;hstsIncludesSubs&lt;/code&gt;, &lt;code&gt;hstsPreload&lt;/code&gt; as structured fields), HTTP→HTTPS redirect&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DNS&lt;/strong&gt; — DNSSEC and CAA records&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cookies&lt;/strong&gt; — Secure, HttpOnly and SameSite attributes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Exposure paths&lt;/strong&gt; — &lt;code&gt;/.git/HEAD&lt;/code&gt;, &lt;code&gt;/.env&lt;/code&gt;, &lt;code&gt;/phpinfo.php&lt;/code&gt;, &lt;code&gt;/wp-login.php&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;JS bundle secret scanning&lt;/strong&gt; — leaked OpenAI, Stripe, AWS, Supabase keys in shipped JavaScript&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What Guardr's v1 doesn't have (yet)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;rawHeaders[]&lt;/code&gt; dump — use a HEAD request if you need raw headers&lt;/li&gt;
&lt;li&gt;History endpoint, compare endpoint and PDF-via-API — these exist in the dashboard but aren't exposed as API endpoints yet&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Other alternatives (honest take)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Mozilla Observatory&lt;/strong&gt; — free, excellent for manual one-off checks, no public API&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Qualys SSL Labs&lt;/strong&gt; — gold standard for deep TLS analysis, doesn't cover headers&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Roll your own&lt;/strong&gt; — 30 lines of Python + cron if you only need HSTS presence&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Guardr is the closest drop-in for the grade-based API + remediation use case. For deep TLS work, SSL Labs is still the right tool. For manual spot checks, Mozilla Observatory is free and great.&lt;/p&gt;




&lt;p&gt;I'm Anatoli, building Guardr solo. The API launched this month specifically to give SecurityHeaders.com users somewhere to land. If there's an endpoint or feature from the old API that doesn't have a Guardr equivalent and it's blocking your migration, &lt;a href="https://guardr.io/contact" rel="noopener noreferrer"&gt;drop me a message&lt;/a&gt; — I want to hear about it.&lt;/p&gt;

&lt;p&gt;Full docs and response samples: &lt;a href="https://guardr.io/docs/api" rel="noopener noreferrer"&gt;guardr.io/docs/api&lt;/a&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>webdev</category>
      <category>devops</category>
      <category>api</category>
    </item>
    <item>
      <title>Hardenize moved to $5K+/year enterprise. Here's the self-serve alternative.</title>
      <dc:creator>Guardr</dc:creator>
      <pubDate>Mon, 23 Mar 2026 19:33:00 +0000</pubDate>
      <link>https://dev.to/guardr/hardenize-moved-to-5kyear-enterprise-heres-the-self-serve-alternative-3dpn</link>
      <guid>https://dev.to/guardr/hardenize-moved-to-5kyear-enterprise-heres-the-self-serve-alternative-3dpn</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This post originally appeared on &lt;a href="https://guardr.io/blog/vs-hardenize/" rel="noopener noreferrer"&gt;guardr.io/blog/vs-hardenize&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Hardenize was one of the best tools for tracking security posture across a portfolio of websites. After Red Sift acquired it, the self-serve tier was removed and pricing moved to $5,000+/year — aimed at enterprise security teams, not agencies or freelancers.&lt;/p&gt;

&lt;p&gt;If you were on the self-serve tier, this post is for you.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you're probably looking for
&lt;/h2&gt;

&lt;p&gt;A replacement that covers the same monitoring surface as Hardenize:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Security headers&lt;/strong&gt; (CSP, HSTS, X-Frame-Options, Referrer-Policy, Permissions-Policy)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TLS and SSL certificate expiry&lt;/strong&gt; — alerts at 30 and 7 days before expiry&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DNS security&lt;/strong&gt; (DNSSEC, CAA records)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cookie attribute checks&lt;/strong&gt; (Secure, HttpOnly, SameSite)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Exposure path detection&lt;/strong&gt; (&lt;code&gt;.git&lt;/code&gt;, &lt;code&gt;.env&lt;/code&gt;, &lt;code&gt;wp-login.php&lt;/code&gt;, &lt;code&gt;phpinfo.php&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Continuous monitoring with alerts&lt;/strong&gt; — not manual spot checks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;...without a $5K/year contract.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Guardr fits
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://guardr.io" rel="noopener noreferrer"&gt;Guardr&lt;/a&gt; is a self-serve security posture monitor built for web agencies and developers managing multiple sites.&lt;/p&gt;

&lt;p&gt;It covers everything above plus uptime monitoring, and includes platform-specific fix instructions per finding — the exact Cloudflare, Nginx, or Apache config snippet, not just a description of the problem.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Hardenize&lt;/th&gt;
&lt;th&gt;Guardr&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Security header monitoring&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TLS / cert expiry alerts&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DNS security checks&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cookie security&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Exposure path detection&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Uptime monitoring&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fix instructions per platform&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Self-serve available&lt;/td&gt;
&lt;td&gt;⛔ Gone&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Starting price&lt;/td&gt;
&lt;td&gt;$5K+/year&lt;/td&gt;
&lt;td&gt;$7/month&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Letter grade, tracked over time
&lt;/h2&gt;

&lt;p&gt;Every site gets an A–F grade based on its full security configuration — TLS, headers, DNS, cookies, and exposure paths. The grade is tracked over time so you can see when a deployment caused a regression, and alerts fire when it drops.&lt;/p&gt;

&lt;h2&gt;
  
  
  Free scanner — no login needed
&lt;/h2&gt;

&lt;p&gt;You can scan any URL for free at &lt;a href="https://guardr.io" rel="noopener noreferrer"&gt;guardr.io&lt;/a&gt; — no account required. You'll get a letter grade and full breakdown of every misconfiguration, with fix instructions included.&lt;/p&gt;

&lt;p&gt;From there you can set up continuous monitoring with one click.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Full comparison at &lt;a href="https://guardr.io/blog/vs-hardenize/" rel="noopener noreferrer"&gt;guardr.io/blog/vs-hardenize&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>security</category>
      <category>devops</category>
      <category>monitoring</category>
    </item>
    <item>
      <title>What Does a Website Security Score Mean?</title>
      <dc:creator>Guardr</dc:creator>
      <pubDate>Sun, 15 Mar 2026 19:20:22 +0000</pubDate>
      <link>https://dev.to/guardr/what-does-a-website-security-score-mean-1kbn</link>
      <guid>https://dev.to/guardr/what-does-a-website-security-score-mean-1kbn</guid>
      <description>&lt;p&gt;You ran a security scan on your website and got a grade. Maybe it's an A. Maybe it's a D. Either way, you're probably wondering: what does this actually mean? Is my site about to get hacked? Are my visitors at risk?&lt;/p&gt;

&lt;p&gt;The short answer: a website security score is a snapshot of how well your site follows publicly recommended security best practices. It doesn't mean you've been breached. It means there are things any browser or any visitor can check about your site and some of them could be configured better.&lt;/p&gt;

&lt;p&gt;Let's break it down.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a security score measures
&lt;/h2&gt;

&lt;p&gt;A website security score evaluates the &lt;strong&gt;publicly visible configuration&lt;/strong&gt; of your website. This isn't about scanning your server's file system or testing for SQL injection. It's about what your site tells every single visitor's browser when they connect.&lt;/p&gt;

&lt;p&gt;Think of it like a building inspection. An inspector doesn't break into your vault — they check whether the doors lock properly, the fire exits work and the smoke detectors are installed. A security score does the same thing for your website.&lt;/p&gt;

&lt;p&gt;Most scanners, including &lt;a href="https://guardr.io" rel="noopener noreferrer"&gt;Guardr&lt;/a&gt; — evaluate five main areas:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. TLS / SSL configuration
&lt;/h3&gt;

&lt;p&gt;TLS (Transport Layer Security) is what makes your site load over HTTPS instead of HTTP. But not all TLS setups are equal. A security scan checks whether your certificate is valid, whether outdated protocol versions like TLS 1.0 and 1.1 are disabled and whether the connection between your visitor and your server is properly encrypted.&lt;/p&gt;

&lt;p&gt;A properly configured TLS setup also means your SSL certificate isn't about to expire without you knowing. Expired certificates trigger browser warnings that immediately drive visitors away — and most site owners don't realize it happened until someone tells them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it matters:&lt;/strong&gt; A weak or misconfigured TLS setup can leave your visitors' data exposed in transit — login credentials, form submissions, payment information. And an expired certificate can take your site's credibility offline in seconds.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Security headers
&lt;/h3&gt;

&lt;p&gt;Security headers are instructions your server sends to the browser with every page load. They tell the browser things like: "don't load scripts from unknown sources," "don't allow this page to be embedded in an iframe," and "always use HTTPS."&lt;/p&gt;

&lt;p&gt;The most important ones include:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Strict-Transport-Security (HSTS)&lt;/strong&gt; — forces HTTPS connections, preventing downgrade attacks where an attacker intercepts the initial HTTP request before it redirects to HTTPS.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Content-Security-Policy (CSP)&lt;/strong&gt; — controls which resources the browser is allowed to load, blocking malicious scripts injected through cross-site scripting (XSS) attacks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;X-Content-Type-Options&lt;/strong&gt; — prevents the browser from guessing file types incorrectly, which attackers can exploit to execute malicious code disguised as harmless files.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;X-Frame-Options&lt;/strong&gt; — blocks clickjacking attacks by preventing your site from being embedded in iframes on malicious pages.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Referrer-Policy&lt;/strong&gt; — controls what information is shared when visitors click links on your site, preventing sensitive URL parameters from leaking to third parties.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Permissions-Policy&lt;/strong&gt; — restricts which browser features (camera, microphone, geolocation) your site can access, reducing the attack surface if your site is ever compromised.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it matters:&lt;/strong&gt; Missing security headers are the single most common misconfiguration on the web. They're free to add, take minutes to configure and protect your visitors from entire classes of attacks. If you fix nothing else, fix your headers first.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Cookie security
&lt;/h3&gt;

&lt;p&gt;If your site sets cookies (and almost every site does — analytics, sessions, preferences), those cookies should be configured with security flags: &lt;code&gt;Secure&lt;/code&gt; (only sent over HTTPS), &lt;code&gt;HttpOnly&lt;/code&gt; (not accessible to JavaScript) and &lt;code&gt;SameSite&lt;/code&gt; (prevents cross-site request forgery).&lt;/p&gt;

&lt;p&gt;Without these flags, cookies become low-hanging fruit for attackers. A cookie without the &lt;code&gt;Secure&lt;/code&gt; flag can be intercepted over an unencrypted connection. A cookie without &lt;code&gt;HttpOnly&lt;/code&gt; can be stolen by a malicious script running on your page. A cookie without &lt;code&gt;SameSite&lt;/code&gt; can be exploited in cross-site request forgery (CSRF) attacks, where an attacker tricks your user's browser into making authenticated requests to your site.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it matters:&lt;/strong&gt; Insecure cookies can be stolen or manipulated, potentially letting an attacker hijack a user's session and act as if they were that user.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. DNS security
&lt;/h3&gt;

&lt;p&gt;Your domain's DNS configuration can include additional security layers that most site owners overlook. DNSSEC (Domain Name System Security Extensions) prevents attackers from redirecting your visitors to a fake version of your site by cryptographically signing your DNS records. CAA (Certificate Authority Authorization) records specify which certificate authorities are allowed to issue certificates for your domain, preventing unauthorized certificate issuance.&lt;/p&gt;

&lt;p&gt;These are often ignored because they're configured at the registrar level, not the server level — meaning they fall through the cracks between "the person who manages the domain" and "the person who manages the server."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it matters:&lt;/strong&gt; Without DNS security, an attacker could intercept your visitors before they even reach your server — and your visitors would have no way to tell the difference.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Exposure and information leakage
&lt;/h3&gt;

&lt;p&gt;This category checks whether your site exposes files or paths that shouldn't be publicly accessible — things like &lt;code&gt;.git&lt;/code&gt; directories, &lt;code&gt;.env&lt;/code&gt; files, &lt;code&gt;wp-admin&lt;/code&gt; login panels, database backup files, or server information headers that reveal your technology stack.&lt;/p&gt;

&lt;p&gt;Every piece of exposed information makes an attacker's job easier. A leaked &lt;code&gt;.env&lt;/code&gt; file could contain API keys, database credentials, or third-party service tokens. An exposed &lt;code&gt;.git&lt;/code&gt; directory could reveal your entire source code. A visible &lt;code&gt;wp-admin&lt;/code&gt; path confirms you're running WordPress and tells attackers exactly where to focus their brute-force attempts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it matters:&lt;/strong&gt; Exposure paths give attackers a roadmap of your infrastructure. The less they know about your stack, the harder their job becomes.&lt;/p&gt;

&lt;h2&gt;
  
  
  How the score is calculated
&lt;/h2&gt;

&lt;p&gt;Different scanners weigh these categories differently. In Guardr, the weighting reflects real-world impact:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TLS / SSL: 28%&lt;/strong&gt; — because encryption is foundational to everything else.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Security Headers: 28%&lt;/strong&gt; — because they're the most actionable and commonly missing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Exposure Paths: 20%&lt;/strong&gt; — because information leakage creates direct, exploitable risk.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cookie Security: 14%&lt;/strong&gt; — because session security matters for any site handling user data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DNS Security: 10%&lt;/strong&gt; — because it's important but less commonly exploited at the SMB level.&lt;/p&gt;

&lt;p&gt;Each category is scored individually based on what's configured correctly versus what's missing or misconfigured. The category scores are then combined into an overall percentage that maps to a letter grade:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Score&lt;/th&gt;
&lt;th&gt;Grade&lt;/th&gt;
&lt;th&gt;What it means&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;90–100&lt;/td&gt;
&lt;td&gt;A&lt;/td&gt;
&lt;td&gt;Excellent — your site follows best practices across the board&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;80–89&lt;/td&gt;
&lt;td&gt;B&lt;/td&gt;
&lt;td&gt;Good — solid foundation with a few misconfigurations to address&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;65–79&lt;/td&gt;
&lt;td&gt;C&lt;/td&gt;
&lt;td&gt;Fair — noticeable gaps that should be fixed soon&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;50–64&lt;/td&gt;
&lt;td&gt;D&lt;/td&gt;
&lt;td&gt;Poor — significant misconfigurations putting visitors at risk&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Below 50&lt;/td&gt;
&lt;td&gt;F&lt;/td&gt;
&lt;td&gt;Critical — immediate attention needed&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Most websites score in the C to B range. If you're there, you're not alone — but you can do better.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a score doesn't tell you
&lt;/h2&gt;

&lt;p&gt;It's important to understand the limits of a security score:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It's not a penetration test.&lt;/strong&gt; A score checks configuration, not whether an attacker can exploit a specific vulnerability in your application code or business logic.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It's not a guarantee.&lt;/strong&gt; An A grade means your publicly visible configuration follows best practices. It doesn't mean your site is unhackable — there is no tool that can promise that.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It's not permanent.&lt;/strong&gt; Configurations change when you update your server, switch hosting providers, deploy new code, or modify your tech stack. A score from last month might not reflect today's reality.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It's not a compliance certificate.&lt;/strong&gt; While a good security score aligns with many compliance requirements (PCI DSS, GDPR technical measures), it doesn't replace a formal compliance audit.&lt;/p&gt;

&lt;p&gt;This is exactly why continuous monitoring matters — a one-time scan tells you where you stand right now, but your security posture can drift without anyone noticing.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to do with your score
&lt;/h2&gt;

&lt;p&gt;If your score isn't where you'd like it to be, here's the good news: most misconfigurations are straightforward to fix. You don't need to hire a security consultant or overhaul your infrastructure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Start with the highest-impact items:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Security headers&lt;/strong&gt; — these are usually the quickest wins. Adding headers like HSTS, X-Content-Type-Options and X-Frame-Options takes minutes on most platforms.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TLS configuration&lt;/strong&gt; — make sure you're running TLS 1.2 or higher and that your certificate is valid and not approaching expiry. If you're on Cloudflare or a modern hosting provider, most of this is handled for you but it's worth verifying.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cookie flags&lt;/strong&gt; — if you control your application's cookie settings, adding &lt;code&gt;Secure&lt;/code&gt;, &lt;code&gt;HttpOnly&lt;/code&gt; and &lt;code&gt;SameSite&lt;/code&gt; flags is usually a small code change or server configuration update.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Exposure paths&lt;/strong&gt; — check whether any sensitive files (&lt;code&gt;.env&lt;/code&gt;, &lt;code&gt;.git&lt;/code&gt;, backups) are publicly accessible and block them at the server level with deny rules.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DNS security&lt;/strong&gt; — enable DNSSEC through your domain registrar and add CAA records to restrict certificate issuance. This is a one-time setup that takes about 10 minutes.&lt;/p&gt;

&lt;p&gt;Each fix compounds. Address the top three items and you'll likely jump an entire letter grade.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why continuous monitoring beats one-time scans
&lt;/h2&gt;

&lt;p&gt;Running a scan once is useful. It gives you a baseline. But websites are not static — you deploy new code, update plugins, switch CDN providers, renew certificates, change server configurations. Any of these can quietly alter your security posture without triggering a single alert.&lt;/p&gt;

&lt;p&gt;A header that was present last week might disappear after a deployment. A certificate that was fine yesterday might expire tomorrow. A new exposed path might appear when a developer pushes a config file they didn't mean to.&lt;/p&gt;

&lt;p&gt;Continuous monitoring catches these changes before they become problems. Instead of remembering to manually check your site every few weeks (and let's be honest, you won't), you get alerted the moment something changes: a header disappears, a certificate is approaching expiry, your score drops.&lt;/p&gt;

&lt;p&gt;That's exactly what &lt;a href="https://guardr.io" rel="noopener noreferrer"&gt;Guardr&lt;/a&gt; is built for. It scans your site on a regular schedule, tracks changes over time and alerts you when something needs attention — so you can fix misconfigurations in minutes instead of discovering them weeks later.&lt;/p&gt;




&lt;p&gt;A security score is a starting point, not a destination. It tells you where you stand, highlights what needs attention and gives you a clear path to improving. The sites that stay secure aren't the ones that scan once and forget — they're the ones that monitor continuously and fix issues as they appear.&lt;/p&gt;

</description>
      <category>websecurity</category>
      <category>security</category>
      <category>webdev</category>
      <category>beginners</category>
    </item>
    <item>
      <title>How to Fix Missing HSTS Header (Step-by-Step)</title>
      <dc:creator>Guardr</dc:creator>
      <pubDate>Wed, 11 Mar 2026 19:01:01 +0000</pubDate>
      <link>https://dev.to/guardr/how-to-fix-missing-hsts-header-step-by-step-2o8c</link>
      <guid>https://dev.to/guardr/how-to-fix-missing-hsts-header-step-by-step-2o8c</guid>
      <description>&lt;p&gt;If you've scanned your website and received a warning about a missing HSTS header, you're not alone. From our internal checks, most of the none technical websites are misconfigured and are missing HSTS header mostly because they are lack of security awareness, this is why we want to raise such awareness. It's one of the most common security findings and one of the most impactful to fix. This guide walks you through what HSTS is, why your site needs it, and how to enable it on every major platform.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's covered
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;What is HSTS and why does it matter?&lt;/li&gt;
&lt;li&gt;How HSTS protects your users&lt;/li&gt;
&lt;li&gt;Before you enable HSTS&lt;/li&gt;
&lt;li&gt;How to add HSTS on Cloudflare&lt;/li&gt;
&lt;li&gt;How to add HSTS on Nginx&lt;/li&gt;
&lt;li&gt;How to add HSTS on Apache&lt;/li&gt;
&lt;li&gt;How to add HSTS on other platforms&lt;/li&gt;
&lt;li&gt;Understanding the HSTS directives&lt;/li&gt;
&lt;li&gt;Common mistakes when enabling HSTS&lt;/li&gt;
&lt;li&gt;HSTS preloading explained&lt;/li&gt;
&lt;li&gt;How to verify HSTS is working&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What is HSTS and why does it matter?
&lt;/h2&gt;

&lt;p&gt;HSTS stands for HTTP Strict Transport Security. It's a security header that tells browsers: "Only connect to this site over HTTPS. Never use HTTP."&lt;/p&gt;

&lt;p&gt;Without HSTS, here's what can happen. A user types &lt;code&gt;yoursite.com&lt;/code&gt; into their browser. The browser first tries &lt;code&gt;http://yoursite.com&lt;/code&gt;. Your server redirects to &lt;code&gt;https://yoursite.com&lt;/code&gt;. That initial HTTP request — before the redirect — is unencrypted and vulnerable. An attacker on the same network (coffee shop Wi-Fi, hotel network, airport) can intercept that first request, steal cookies, inject malicious content, or redirect the user to a fake version of your site. This is called a protocol downgrade attack.&lt;/p&gt;

&lt;p&gt;HSTS eliminates this window of vulnerability. Once a browser sees the HSTS header, it remembers: "This site is HTTPS-only." Every future visit goes directly to HTTPS — no HTTP request, no redirect, no attack window.&lt;/p&gt;

&lt;p&gt;This isn't a theoretical risk. SSL stripping attacks are well-documented and tools to execute them are freely available. If your site handles any user data — logins, forms, personal information, payments — HSTS should be considered essential.&lt;/p&gt;

&lt;h2&gt;
  
  
  How HSTS protects your users
&lt;/h2&gt;

&lt;p&gt;HSTS provides three specific protections:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No protocol downgrade.&lt;/strong&gt; Browsers refuse to connect over HTTP, even if the user types &lt;code&gt;http://&lt;/code&gt; explicitly or clicks an old HTTP link. The browser automatically upgrades to HTTPS before making the request.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No mixed content fallback.&lt;/strong&gt; If any resource on your page tries to load over HTTP, the browser blocks or upgrades it. This prevents attackers from injecting content through insecure resource loads.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cookie protection.&lt;/strong&gt; Without HSTS, cookies set without the Secure flag could leak over an HTTP connection. HSTS ensures the connection is always encrypted, adding a layer of protection even if cookie flags aren't perfect.&lt;/p&gt;

&lt;h2&gt;
  
  
  Before you enable HSTS
&lt;/h2&gt;

&lt;p&gt;HSTS is powerful, but it's also a commitment. Once a browser caches your HSTS policy, it will refuse to connect over HTTP until the max-age expires. If your HTTPS setup has problems, users won't see a warning — they'll see a hard error with no way to bypass it.&lt;/p&gt;

&lt;p&gt;Before enabling HSTS, verify these things:&lt;/p&gt;

&lt;p&gt;Your SSL/TLS certificate is valid and not expiring soon. All pages on your site load correctly over HTTPS. All resources (images, scripts, stylesheets, fonts) are served over HTTPS — no mixed content. If using &lt;code&gt;includeSubDomains&lt;/code&gt;, every subdomain also works over HTTPS. Your HTTP-to-HTTPS redirect is working correctly (301 permanent redirect).&lt;/p&gt;

&lt;p&gt;If any of these aren't ready, fix them first. Start with a short &lt;code&gt;max-age&lt;/code&gt; (like 300 seconds / 5 minutes) to test safely. Once everything works, increase to the recommended value.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to add HSTS on Cloudflare
&lt;/h2&gt;

&lt;p&gt;Cloudflare offers two approaches.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Option 1: Cloudflare Dashboard (easiest)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Go to your Cloudflare dashboard, select your site, then navigate to SSL/TLS → Edge Certificates. Scroll down to find the HSTS setting and click "Enable HSTS." Cloudflare will show you a confirmation dialog explaining the implications. Configure it with max-age of 12 months, includeSubDomains on, and preload on.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Option 2: &lt;code&gt;_headers&lt;/code&gt; file (for Cloudflare Pages)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you're using Cloudflare Pages, create or edit a &lt;code&gt;_headers&lt;/code&gt; file in your project's output directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;/*
  Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;/*&lt;/code&gt; means this header applies to all pages. Deploy your site and the header will be served on every response.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to add HSTS on Nginx
&lt;/h2&gt;

&lt;p&gt;Add one line inside your &lt;code&gt;server&lt;/code&gt; block for the HTTPS configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;listen&lt;/span&gt; &lt;span class="mi"&gt;443&lt;/span&gt; &lt;span class="s"&gt;ssl&lt;/span&gt; &lt;span class="s"&gt;http2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;server_name&lt;/span&gt; &lt;span class="s"&gt;example.com&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;# Add HSTS header&lt;/span&gt;
    &lt;span class="kn"&gt;add_header&lt;/span&gt; &lt;span class="s"&gt;Strict-Transport-Security&lt;/span&gt; &lt;span class="s"&gt;"max-age=31536000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="kn"&gt;includeSubDomains&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="kn"&gt;preload"&lt;/span&gt; &lt;span class="s"&gt;always&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;# ... rest of your config&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;always&lt;/code&gt; keyword is important — it ensures the header is sent even on error responses (4xx, 5xx). Without it, Nginx only adds the header on successful responses.&lt;/p&gt;

&lt;p&gt;Make sure you only add HSTS to your HTTPS server block, not the HTTP one. The HTTP block should only contain the redirect to HTTPS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;listen&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;server_name&lt;/span&gt; &lt;span class="s"&gt;example.com&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;301&lt;/span&gt; &lt;span class="s"&gt;https://&lt;/span&gt;&lt;span class="nv"&gt;$host$request_uri&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After editing, test and reload:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nginx &lt;span class="nt"&gt;-t&lt;/span&gt;
systemctl reload nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How to add HSTS on Apache
&lt;/h2&gt;

&lt;p&gt;Enable the &lt;code&gt;headers&lt;/code&gt; module if it isn't already, then add the header in your VirtualHost configuration or &lt;code&gt;.htaccess&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight apache"&gt;&lt;code&gt;&lt;span class="c"&gt;# Enable module (if not already)&lt;/span&gt;
&lt;span class="c"&gt;# a2enmod headers&lt;/span&gt;

&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nl"&gt;VirtualHost&lt;/span&gt;&lt;span class="sr"&gt; *:443&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="nc"&gt;ServerName&lt;/span&gt; example.com

    &lt;span class="c"&gt;# Add HSTS header&lt;/span&gt;
    &lt;span class="nc"&gt;Header&lt;/span&gt; &lt;span class="ss"&gt;always&lt;/span&gt; &lt;span class="ss"&gt;set&lt;/span&gt; Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"

    &lt;span class="c"&gt;# ... rest of your config&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nl"&gt;VirtualHost&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or in &lt;code&gt;.htaccess&lt;/code&gt; (if your host supports it):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight apache"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nl"&gt;IfModule&lt;/span&gt;&lt;span class="sr"&gt; mod_headers.c&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="nc"&gt;Header&lt;/span&gt; &lt;span class="ss"&gt;always&lt;/span&gt; &lt;span class="ss"&gt;set&lt;/span&gt; Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nl"&gt;IfModule&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Restart Apache after changes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;systemctl restart apache2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How to add HSTS on other platforms
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Vercel&lt;/strong&gt; — add to &lt;code&gt;vercel.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"headers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/(.*)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"headers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"key"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Strict-Transport-Security"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"max-age=31536000; includeSubDomains; preload"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Netlify&lt;/strong&gt; — add to &lt;code&gt;_headers&lt;/code&gt; file or &lt;code&gt;netlify.toml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="nn"&gt;[[headers]]&lt;/span&gt;
  &lt;span class="py"&gt;for&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"/*"&lt;/span&gt;
  &lt;span class="nn"&gt;[headers.values]&lt;/span&gt;
    &lt;span class="py"&gt;Strict-Transport-Security&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="py"&gt;"max-age&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;31536000&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="err"&gt;includeSubDomains;&lt;/span&gt; &lt;span class="err"&gt;preload&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;AWS CloudFront&lt;/strong&gt; — use a Response Headers Policy in the CloudFront distribution settings. Navigate to Policies → Response headers → Create policy → Security headers → Enable Strict-Transport-Security.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;WordPress&lt;/strong&gt; — if you can't edit server config, use a security plugin like "HTTP Headers" or "Really Simple SSL" which can add HSTS through PHP. However, server-level configuration is always preferred.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding the HSTS directives
&lt;/h2&gt;

&lt;p&gt;The full recommended HSTS header looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each part serves a specific purpose:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;max-age=31536000&lt;/code&gt;&lt;/strong&gt; tells the browser how long to remember the HSTS policy, in seconds. 31536000 seconds equals one year. During this time, the browser will never attempt an HTTP connection. The timer resets on every visit, so regular visitors stay protected indefinitely. For initial testing, use &lt;code&gt;max-age=300&lt;/code&gt; (5 minutes). Once confirmed working, increase to a full year.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;includeSubDomains&lt;/code&gt;&lt;/strong&gt; extends the policy to every subdomain under your domain. If you set HSTS on &lt;code&gt;example.com&lt;/code&gt; with includeSubDomains, then &lt;code&gt;api.example.com&lt;/code&gt;, &lt;code&gt;blog.example.com&lt;/code&gt;, and &lt;code&gt;staging.example.com&lt;/code&gt; are all forced to HTTPS as well. Only add this if every subdomain supports HTTPS. One subdomain without a valid certificate will become completely inaccessible.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;preload&lt;/code&gt;&lt;/strong&gt; signals that you want your domain added to browser HSTS preload lists. These are lists compiled into Chrome, Firefox, Safari, and Edge that force HTTPS from the very first visit — not just after the browser first sees your header. To actually get preloaded, you need to submit your domain at hstspreload.org after adding the header.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common mistakes when enabling HSTS
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Setting max-age too high on the first try.&lt;/strong&gt; If you discover a problem after setting a one-year max-age, visitors' browsers will refuse HTTP connections for up to a year. Start with 5 minutes, then 1 day, then 1 week, then 1 year.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Adding includeSubDomains when subdomains aren't ready.&lt;/strong&gt; If &lt;code&gt;staging.example.com&lt;/code&gt; runs on HTTP or has an expired certificate, it becomes unreachable. Audit all subdomains first.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Only adding HSTS to some pages.&lt;/strong&gt; HSTS should be on every response from your domain. Use the wildcard path (&lt;code&gt;/*&lt;/code&gt; in Cloudflare/Netlify) or add it at the server level in Nginx/Apache.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Adding HSTS to HTTP responses.&lt;/strong&gt; The header should only be served over HTTPS. Browsers ignore HSTS headers received over HTTP (for good reason — an attacker could inject a fake one). Your HTTP server block should only redirect to HTTPS.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Forgetting about cookies.&lt;/strong&gt; HSTS protects the transport layer, but you should also set the &lt;code&gt;Secure&lt;/code&gt; flag on all cookies to ensure they're never sent over HTTP. HSTS and Secure cookies work together.&lt;/p&gt;

&lt;h2&gt;
  
  
  HSTS preloading explained
&lt;/h2&gt;

&lt;p&gt;The HSTS preload list is a registry of domains that browsers treat as HTTPS-only from the very first connection. Without preloading, a user's first visit is still vulnerable because the browser hasn't seen your HSTS header yet. Preloading eliminates this gap.&lt;/p&gt;

&lt;p&gt;To qualify for preloading, your site must serve a valid HSTS header with &lt;code&gt;max-age&lt;/code&gt; of at least one year (31536000), include the &lt;code&gt;includeSubDomains&lt;/code&gt; directive, include the &lt;code&gt;preload&lt;/code&gt; directive, and redirect all HTTP traffic to HTTPS.&lt;/p&gt;

&lt;p&gt;Submit your domain at &lt;a href="https://hstspreload.org" rel="noopener noreferrer"&gt;hstspreload.org&lt;/a&gt; after meeting these requirements. The submission is reviewed and, once accepted, your domain is hardcoded into browser source code. This process takes weeks to months — browsers need to ship updates that include the new list.&lt;/p&gt;

&lt;p&gt;A warning: removing your domain from the preload list is difficult and slow. Only preload domains you're certain will stay on HTTPS permanently.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to verify HSTS is working
&lt;/h2&gt;

&lt;p&gt;After deploying, verify with any of these methods:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Using curl:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-I&lt;/span&gt; https://yoursite.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Look for &lt;code&gt;Strict-Transport-Security&lt;/code&gt; in the response headers. You should see your full policy with max-age, includeSubDomains, and preload.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Using browser DevTools:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Open your site in Chrome or Firefox, press F12, go to the Network tab, click the first request (your domain), and check the Response Headers section.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Using Guardr:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/"&gt;Scan your site for free&lt;/a&gt; — Guardr checks your HSTS configuration and tells you exactly what's missing or misconfigured. If your HSTS is working correctly, the TLS/SSL score reflects it. If something is off — missing includeSubDomains, short max-age, or HSTS not present at all — you'll see a specific finding with the exact fix.&lt;/p&gt;




&lt;p&gt;HSTS is one of the highest-impact security improvements you can make. It takes one line of configuration, costs nothing, and protects every user on every visit. If your site is served over HTTPS (and it should be), there's no reason not to enable it.&lt;/p&gt;

&lt;p&gt;Start with a short max-age, verify everything works, then commit to a full year. Your users and your security score will thank you.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>security</category>
      <category>securityheaders</category>
      <category>guide</category>
    </item>
  </channel>
</rss>
