checker: align X-XSS-Protection severities with OWASP

Absent is now OK (OWASP recommends leaving it unset or set to 0),
and filtering mode (bare 1 or 1; report=...) is Warn since selective
script rewriting can itself introduce XSS. 1; mode=block stays Info.
This commit is contained in:
nemunaire 2026-06-18 10:50:51 +09:00
commit a652692ba4
3 changed files with 8 additions and 6 deletions

View file

@ -22,7 +22,7 @@ relies on TLS for transport.
| `http.csp` | Verifies the presence and quality of the Content-Security-Policy header on HTTPS responses. | WARNING | | `http.csp` | Verifies the presence and quality of the Content-Security-Policy header on HTTPS responses. | WARNING |
| `http.x_frame_options` | Verifies that responses set X-Frame-Options or a CSP frame-ancestors directive. | WARNING | | `http.x_frame_options` | Verifies that responses set X-Frame-Options or a CSP frame-ancestors directive. | WARNING |
| `http.x_content_type_options` | Verifies that responses set X-Content-Type-Options: nosniff. | WARNING | | `http.x_content_type_options` | Verifies that responses set X-Content-Type-Options: nosniff. | WARNING |
| `http.x_xss_protection` | Reports the value of the legacy X-XSS-Protection header (disabled is preferred; CSP is the proper replacement). | INFO | | `http.x_xss_protection` | Reports the legacy X-XSS-Protection header; warns on filtering mode (can introduce XSS), absent/`0` are fine, CSP is the real defense. | WARNING |
| `http.referrer_policy` | Verifies that responses set a Referrer-Policy header with a privacy-preserving value. | WARNING | | `http.referrer_policy` | Verifies that responses set a Referrer-Policy header with a privacy-preserving value. | WARNING |
| `http.permissions_policy` | Verifies that the Permissions-Policy header restricts powerful APIs (camera, microphone, geolocation, …). | WARNING | | `http.permissions_policy` | Verifies that the Permissions-Policy header restricts powerful APIs (camera, microphone, geolocation, …). | WARNING |
| `http.coop` | Verifies the Cross-Origin-Opener-Policy (COOP) header for cross-origin process isolation. | WARNING | | `http.coop` | Verifies the Cross-Origin-Opener-Policy (COOP) header for cross-origin process isolation. | WARNING |

View file

@ -63,9 +63,9 @@ func init() {
Inspect: inspectXXSSProtection, Inspect: inspectXXSSProtection,
OnMissing: func(_ HTTPProbe, _ sdk.CheckerOptions) []HeaderResult { OnMissing: func(_ HTTPProbe, _ sdk.CheckerOptions) []HeaderResult {
return []HeaderResult{{ return []HeaderResult{{
Status: sdk.StatusInfo, Status: sdk.StatusOK,
Suffix: "absent", Suffix: "absent",
Message: "X-XSS-Protection is not set; CSP is the recommended replacement.", Message: "X-XSS-Protection is not set, which is acceptable (OWASP recommends leaving it unset or setting `0`); CSP is the proper protection.",
}} }}
}, },
})) }))
@ -235,8 +235,8 @@ func inspectXXSSProtection(value string, _ HTTPProbe, _ sdk.CheckerOptions) []He
}} }}
default: default:
return []HeaderResult{{ return []HeaderResult{{
Status: sdk.StatusInfo, Suffix: "enabled", Status: sdk.StatusWarn, Suffix: "filtering",
Message: "X-XSS-Protection is enabled. Modern browsers ignore this header; CSP is the proper replacement.", Message: "X-XSS-Protection is in filtering mode (e.g. `1` or `1; report=...`). Selective script rewriting can itself introduce XSS in otherwise-safe pages. Set `0` or use `1; mode=block`, and rely on CSP instead.",
}} }}
} }
} }

View file

@ -260,9 +260,11 @@ func TestXXSSProtectionRule(t *testing.T) {
want sdk.Status want sdk.Status
code string code string
}{ }{
{"", sdk.StatusInfo, "http.x_xss_protection.absent"}, {"", sdk.StatusOK, "http.x_xss_protection.absent"},
{"0", sdk.StatusOK, "http.x_xss_protection.disabled"}, {"0", sdk.StatusOK, "http.x_xss_protection.disabled"},
{"1; mode=block", sdk.StatusInfo, "http.x_xss_protection.enabled"}, {"1; mode=block", sdk.StatusInfo, "http.x_xss_protection.enabled"},
{"1", sdk.StatusWarn, "http.x_xss_protection.filtering"},
{"1; report=https://example.com/r", sdk.StatusWarn, "http.x_xss_protection.filtering"},
} }
for _, c := range cases { for _, c := range cases {
p := httpsProbe("a:443") p := httpsProbe("a:443")