Security Headers (security-headers)
Summary
Checks six security response headers (HSTS, CSP, X-Content-Type-Options, and related headers).
Classification
- Category:
SECURITY - Plugin id:
security-headers - Version:
1.0.0 - Target types:
WEBSITE,API,WEBSHOP - Weight class:
LIGHT - Risk level: not set on plugin object
- Browser required: No (HTTP / Node / other — see source)
- Tier / group: Tier 1 — HTTP-only
Schedule
- scheduleHints:
{ defaultInterval: '0 */2 * * *', priority: 5 } - Prerequisites: None declared on this plugin.
Configurable inputs
Public keys are derived from inputSchema: z.object({ ... }) (underscore-prefixed keys are runtime-only and omitted here).
| Field | Notes |
|---|---|
timeout |
Zod field in inputSchema — see source for defaults, min/max, and .describe(). |
Runtime / injected config
- None documented beyond standard worker context (
target,config,logger,reportProgress). Underscore-prefixed keys are internal.
Checks that produce findings
These checks run inside this plugin during a single test run. They are not separate tests in the database — each becomes a Finding linked to the Run for security-headers.
| Check | Typical severity | Why |
|---|---|---|
| Missing Strict-Transport-Security | WARNING | Without HSTS, first visits and mixed-content fixes can still downgrade to HTTP, enabling SSL-stripping on untrusted networks. |
| Missing Content-Security-Policy | WARNING | No CSP means inline scripts and arbitrary third-party origins are not restricted — XSS payloads face fewer browser-enforced limits. |
| Missing X-Content-Type-Options | WARNING | Browsers may MIME-sniff responses (e.g. treat an uploaded “image” as HTML/JS), a common path to stored XSS on user-generated content. |
| Missing X-Frame-Options | WARNING | The page can be embedded in a malicious iframe for clickjacking — tricking logged-in users into clicking hidden actions (pay, delete, transfer). |
| Missing Referrer-Policy | INFO | Full referrer URLs may leak path or query tokens to third-party analytics, ads, or CDN logs on off-site navigation. |
| Missing Permissions-Policy | INFO | Camera, mic, geolocation, and payment APIs are not explicitly denied at the header level, widening impact if script is injected. |
How each check works
- Fetch — Sends a single HEAD request to the target URL via
fetchTarget()(default timeout 10s,TesteBot/1.0user agent). - Header scan — Iterates six expected headers (
strict-transport-security,content-security-policy,x-content-type-options,x-frame-options,referrer-policy,permissions-policy). Case-insensitive lookup viaHeaders.get(). - Finding rule — If a header is absent, emits one finding with severity from
EXPECTED_HEADERS(four WARNING, two INFO). Does not inspect header values — weak CSP or short HSTSmax-agepass if the header exists. - Run outcome —
statusFromFindings()maps severities to run status. Score =(headersPresent / 6) × 100. Metrics record counts and HTTP status.
Caveats and concerns
- HEAD vs GET — Some CDNs omit security headers on HEAD but add them on GET; a passing HEAD check may not reflect browser traffic.
- Presence-only — A site with
Content-Security-Policy: *orX-Frame-Options: ALLOWALLwould not fail; only existence is checked. - Single URL — Only the configured target URL is checked (homepage or API root), not every route or asset domain.
- API targets — JSON/API responses may legitimately omit framing or CSP headers that matter on HTML pages; findings may be noisy on pure API endpoints.
Source
packages/test-plugins/src/plugins/security-headers.ts