We scanned our own websites with KENSAI and found critical NIS2 compliance gaps. Missing HTTP security headers brought two of our three domains to Grade B (0.786). Here's exactly what was wrong, what NIS2 articles were at risk, and how 30 minutes of Caddy configuration fixed everything.
We build a security scanning platform. We preach NIS2 compliance to our customers. And then we ran KENSAI on our own domains โ and found that two out of three were non-compliant.
No vulnerabilities, no breaches. Just missing HTTP security headers โ the kind of silent gap that regulators check first and attackers exploit second. Under the NIS2 Directive (Art. 21, ยง2), these headers aren't optional for regulated entities. They're a baseline hygiene requirement.
Here's what we found, and how fast we fixed it.
We ran KENSAI's automated NIS2 compliance scan across all three portfolio domains on March 15, 2026:
kensai.app scored near-perfect at 0.997 because it was already running the correct Caddy header configuration. The other two domains โ brnz.ai and codeforceai.com โ were both at 0.786, each missing the same six critical security headers.
Six HTTP response headers were absent from both failing domains. Each one maps directly to NIS2 Directive requirements:
| Missing Header | Purpose | NIS2 Reference | Status |
|---|---|---|---|
Strict-Transport-Security |
Forces HTTPS, prevents protocol downgrade attacks | Art. 21(2)(h) โ Secure communications | โ MISSING |
Content-Security-Policy |
Blocks XSS, code injection, data exfiltration | Art. 21(2)(d) โ Supply chain security | โ MISSING |
X-Frame-Options |
Prevents clickjacking / UI redress attacks | Art. 21(2)(b) โ Incident prevention | โ MISSING |
X-Content-Type-Options |
Stops MIME-sniffing attacks | Art. 21(2)(b) โ Basic cyber hygiene | โ MISSING |
Referrer-Policy |
Controls referrer data leakage to third parties | Art. 21(2)(e) โ Data security policies | โ MISSING |
Permissions-Policy |
Restricts browser API access (camera, mic, geolocation) | Art. 25 โ Security by design | โ MISSING |
We use Caddy as our reverse proxy. The fix was a single, reusable header block that we could apply to all domains. Here's exactly what we added:
# Global header snippet โ add to all production sites
(security_headers) {
header {
# Force HTTPS โ NIS2 Art. 21(2)(h): secure communications
Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
# Block XSS & injection โ NIS2 Art. 21(2)(d): supply chain security
Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' https://fonts.googleapis.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com; img-src 'self' data: https:; connect-src 'self' https:; frame-ancestors 'none'"
# Prevent clickjacking โ NIS2 Art. 21(2)(b)
X-Frame-Options "DENY"
# Stop MIME-sniffing โ NIS2 Art. 21(2)(b)
X-Content-Type-Options "nosniff"
# Limit referrer leakage โ NIS2 Art. 21(2)(e)
Referrer-Policy "strict-origin-when-cross-origin"
# Restrict browser APIs โ NIS2 Art. 25: security by design
Permissions-Policy "camera=(), microphone=(), geolocation=(), payment=(), usb=(), interest-cohort=()"
# Remove server fingerprinting
-Server
-X-Powered-By
}
}
Then we imported the snippet into each site block:
# brnz.ai
brnz.ai, www.brnz.ai {
import security_headers
reverse_proxy localhost:3001
}
# codeforceai.com
codeforceai.com, www.codeforceai.com {
import security_headers
reverse_proxy localhost:3002
}
Reload Caddy, verify headers in browser DevTools, done:
caddy reload --config /etc/caddy/Caddyfile
Every NIS2-regulated entity is expected to have basic HTTP security headers in place. Regulators are increasingly running automated scans during audits. A missing Strict-Transport-Security header isn't a minor omission โ it's evidence of inadequate risk management under Art. 21(2).
We build compliance tools and still had two Grade B sites. This isn't embarrassing โ it's a reminder that configuration drift happens. A domain launched quickly, a Caddyfile that wasn't synced, a missing import. Automated scanning catches what manual audits miss.
Six missing headers. Thirty lines of Caddy configuration. Thirty minutes of work. The gap between Grade B and Grade A is not a month-long project โ it's an afternoon. The hard part is knowing the gap exists in the first place.
By extracting the headers into a (security_headers) snippet, any new domain we add automatically gets full NIS2 header coverage by including a single import line. Compliance becomes the default, not an afterthought.
If you're under NIS2 โ or preparing for an audit โ your HTTP security headers are one of the first things regulators check. They're fast to scan, unambiguous to evaluate, and trivial to fix. There's no excuse for a Grade B when a Grade A takes 30 minutes.
Run the scan. Read the report. Fix what's flagged. Re-scan to confirm.
Run the same scan we ran on our own domains. Get your NIS2 compliance grade, see exactly which headers are missing, and get a remediation report you can act on immediately.
Start Free NIS2 Scan โ๐ก๏ธ Is your website secure?
Discover vulnerabilities before attackers do.
Scan your website for free โ