← All posts
1 March 2026·8 min read

We Scanned Ourselves and Found 6 Security Issues

We pointed KrakenProbe at krakenprobe.com. It found missing headers, no CSP, information leaks, and platform-wrong remediation. Here's every issue and exactly how we fixed each one.

case studysecurity headersweb securityCSPNetlify

There's no better test for a security scanner than scanning itself. So we pointed KrakenProbe at krakenprobe.com, hit Scan, and waited 1.2 seconds for the verdict.

Grade: B. Score: 76 out of 100. Six issues found. Not terrible — but not great for a security tool. Here's every finding, why it matters, and the exact fix we shipped.

The setup

KrakenProbe is a Next.js application hosted on Netlify. It uses GitHub OAuth for authentication, Google Fonts for typography, and PostHog for analytics (opt-in only). The site makes API calls to OpenAI for AI-powered analysis. Pretty standard modern web stack.

We ran the scan with AI analysis enabled using GPT-4o-mini. Total cost: $0.002. The AI graded us, identified the top priorities, and generated remediation code. Then we had to eat our own humble pie and actually implement the fixes.

Issue #1: Missing Content-Security-Policy

Severity: High. This was the biggest one. No CSP header at all. Content-Security-Policy is your primary defence against cross-site scripting (XSS) attacks — it tells the browser exactly which sources are allowed to load scripts, styles, fonts, and other resources. Without it, any injected script runs with full privileges.

The tricky part: our initial CSP was too generic. We were tempted to set default-src 'self' and call it done. But that would break Google Fonts, GitHub avatars, and PostHog analytics. A CSP that breaks your site is worse than no CSP — you'll just remove it.

We audited every external resource KrakenProbe loads and built a CSP that allows exactly what we need and nothing else:

Content-Security-Policy:
  default-src 'self';
  script-src 'self' 'unsafe-inline' 'unsafe-eval' https://us.i.posthog.com;
  style-src 'self' 'unsafe-inline' https://fonts.googleapis.com;
  font-src 'self' https://fonts.gstatic.com;
  img-src 'self' data: https://avatars.githubusercontent.com;
  connect-src 'self' https://us.i.posthog.com;
  frame-ancestors 'none';
  base-uri 'self';
  form-action 'self'

Note: Next.js currently requires 'unsafe-inline' and 'unsafe-eval' for script-src due to how it handles hydration. That's not ideal, but it's a known Next.js limitation. The rest of the policy is locked down tight — frame-ancestors 'none' prevents clickjacking, base-uri 'self' prevents base tag hijacking, and form-action 'self' prevents form data exfiltration.

Issue #2: Missing Permissions-Policy

Severity: Medium. Permissions-Policy (formerly Feature-Policy) controls which browser APIs your site can access. Without it, any script on your page could request camera access, microphone access, or geolocation data. KrakenProbe is a security scanner — it has no business accessing your webcam.

Permissions-Policy: camera=(), microphone=(), geolocation=(), interest-cohort=()

The empty parentheses mean "nobody, not even us." We also disabled interest-cohort to opt out of Google's FLoC tracking. Simple header, big privacy win.

Issue #3: Server header information leak

Severity: Low. Our response headers included Server: Netlify and X-Powered-By: Next.js. These tell attackers exactly what technology stack we're running, letting them target known vulnerabilities for those specific platforms.

Ironically, this information leak is what powers one of KrakenProbe's best features — platform detection. When our scanner sees Server: Netlify, it generates Netlify-specific remediation (netlify.toml config) instead of generic Nginx add_header commands. So the leak is useful for us as a scanner but bad practice for the site being scanned.

On Netlify, you can't fully suppress the Server header — Netlify adds it at the edge. The X-Powered-By header can be removed in next.config.js with poweredByHeader: false. We accepted this as a known limitation of the platform and moved on. Sometimes perfect security isn't achievable, and knowing why is what matters.

Issue #4: Missing HSTS preload

Severity: Medium. We had HTTPS but weren't telling browsers to enforce it permanently. Without Strict-Transport-Security, a user's first visit could be intercepted over HTTP before the redirect to HTTPS kicks in. We added the full HSTS header with preload:

Strict-Transport-Security: max-age=63072000; includeSubDomains; preload

max-age=63072000 is two years. includeSubDomains extends protection to any subdomains we might create. preload means we can submit to browser preload lists so even the very first visit is protected. This is one of those "set it and forget it" headers — zero downside if you're committed to HTTPS.

Issue #5: Netlify headers not reaching pages

This was the sneaky one. We had security headers configured in netlify.toml from day one. They looked correct. But when we actually checked the response headers with curl, some were missing from HTML page responses.

The reason: Netlify's Next.js plugin (@netlify/plugin-nextjs) serves pages through serverless functions. The [[headers]] rules in netlify.toml only apply to truly static files — images, fonts, CSS. Server-rendered pages bypass them entirely.

The fix was moving all security headers into next.config.js using the headers() function, which Next.js applies to every response regardless of how it's served:

// next.config.js
async headers() {
  return [
    {
      source: "/(.*)",
      headers: [
        { key: "Content-Security-Policy", value: "..." },
        { key: "X-Frame-Options", value: "DENY" },
        { key: "X-Content-Type-Options", value: "nosniff" },
        { key: "Referrer-Policy", value: "strict-origin-when-cross-origin" },
        { key: "Permissions-Policy", value: "..." },
        { key: "Strict-Transport-Security", value: "..." },
      ],
    },
  ];
}

We kept the netlify.toml headers as a belt-and-braces fallback for static assets, but next.config.js is what actually delivers the headers on page loads. This is a gotcha that will catch anyone running Next.js on Netlify.

Issue #6: AI remediation showing wrong platform

This one was a bug in KrakenProbe itself. When the scan told us to add CSP, the suggested fix was:

add_header Content-Security-Policy "default-src 'self';" always;

That's Nginx syntax. We're on Netlify. The AI was giving generic Nginx remediation regardless of the actual platform because our analyzer prompt told it "No multi-platform." We were sending the scan results to OpenAI but stripping out the rawHeaders that contained Server: Netlify — so the AI had no way to know what platform it was looking at.

We fixed this by adding platform detection to the analyzer. It reads the Server header, X-Powered-By, and Via header from the scan results, identifies the hosting platform, and tells the AI to generate platform-specific remediation. Now scanning a Netlify site shows netlify.toml config first, a Vercel site shows vercel.json, Cloudflare shows _headers file, and so on.

The result

After shipping all six fixes, we rescanned. The headers category jumped from D to A. Overall score went from 76 to the high 80s. The remaining points are lost on the Server header leak (can't fix on Netlify) and Next.js requiring unsafe-eval in the CSP (can't fix until Next.js changes their hydration approach).

Total time from scan to fix: about 30 minutes. Total cost: $0.002 for the AI scan, plus another $0.002 for the verification rescan. Four-tenths of a cent to find and fix six real security issues.

What we learned

First: always verify headers are actually being served, not just configured. Our netlify.toml looked perfect but the headers weren't reaching the browser. Trust curl, not config files.

Second: CSP is not a one-size-fits-all header. You need to audit what your site actually loads and build the policy around that. A CSP that's too restrictive breaks your site; a CSP that's too loose doesn't protect it.

Third: platform-specific remediation matters. Telling a Netlify user to edit nginx.conf is worse than useless — it wastes their time and makes them trust your tool less. This finding directly improved KrakenProbe's AI analysis for every user.

And fourth: dogfooding works. We built a security scanner and it immediately found real issues on its own site. If that's not a product validation, what is?

Scan your own site

Curious what KrakenProbe would find on your site? It takes 30 seconds and costs less than a penny. Sign in with GitHub and run your first scan — you might be surprised what's missing.

Check your site now

Run a free security scan — 8 scanners check your site in seconds.

Scan your website