Deepen CSP, Permissions-Policy and cookie audits

Detect CSP weaknesses individually (unsafe-inline, unsafe-eval, missing
default-src/script-src, permissive sources on script-src or its
default-src fallback) instead of a single catch-all "unsafe" code, and
honour CSP3 fetch-directive fallback via EffectiveSources/WildcardSource
helpers. Validate Permissions-Policy values: warn when a powerful
feature (camera, microphone, geolocation, payment, sensors, …) is
granted to all origins. Add a SameSite aggregate state on cookie audits
so callers get the global ratio alongside per-cookie diagnostics.
This commit is contained in:
nemunaire 2026-04-27 11:50:42 +07:00
commit 603e93355b
8 changed files with 738 additions and 305 deletions

View file

@ -48,12 +48,26 @@ func TestCookieFlagsRule_Issues(t *testing.T) {
{Name: "none-without-secure", Secure: false, HttpOnly: true, SameSite: "None"},
}
states := runRule(t, &cookieFlagsRule{}, &HTTPData{Probes: []HTTPProbe{p}}, nil)
if len(states) != len(p.Cookies) {
t.Fatalf("got %d states, want %d", len(states), len(p.Cookies))
// Per-cookie diagnostics + a single SameSite aggregate (1 cookie out
// of 4 is missing SameSite).
if len(states) != len(p.Cookies)+1 {
t.Fatalf("got %d states, want %d", len(states), len(p.Cookies)+1)
}
mustStatus(t, states, sdk.StatusWarn)
// Check each diagnostic mentions the cookie name and a relevant phrase.
if !hasCode(states, "http.cookie_flags.samesite_missing") {
t.Errorf("missing samesite_missing aggregate: %+v", states)
}
for _, st := range states {
if st.Code == "http.cookie_flags.samesite_missing" {
if !strings.Contains(st.Message, "1 of 4") {
t.Errorf("aggregate message %q should mention 1 of 4", st.Message)
}
}
}
// Check each per-cookie diagnostic mentions the cookie name and a
// relevant phrase.
wantSubstr := map[string]string{
"no-secure": "missing Secure",
"no-httponly": "missing HttpOnly",
@ -61,6 +75,9 @@ func TestCookieFlagsRule_Issues(t *testing.T) {
"none-without-secure": "SameSite=None requires Secure",
}
for _, st := range states {
if st.Code != "http.cookie_flags.weak" {
continue
}
matched := false
for name, phrase := range wantSubstr {
if strings.Contains(st.Message, name) && strings.Contains(st.Message, phrase) {
@ -74,6 +91,26 @@ func TestCookieFlagsRule_Issues(t *testing.T) {
}
}
func TestCookieFlagsRule_SameSiteAggregateOnly(t *testing.T) {
// Two cookies, both otherwise compliant but missing SameSite. We
// expect 2 per-cookie warnings + 1 aggregate.
p := httpsProbe("a:443")
p.Cookies = []CookieInfo{
{Name: "a", Secure: true, HttpOnly: true, SameSite: ""},
{Name: "b", Secure: true, HttpOnly: true, SameSite: ""},
}
states := runRule(t, &cookieFlagsRule{}, &HTTPData{Probes: []HTTPProbe{p}}, nil)
mustStatus(t, states, sdk.StatusWarn)
if !hasCode(states, "http.cookie_flags.samesite_missing") {
t.Fatalf("missing aggregate state: %+v", states)
}
for _, st := range states {
if st.Code == "http.cookie_flags.samesite_missing" && !strings.Contains(st.Message, "2 of 2") {
t.Errorf("aggregate should report 2 of 2, got %q", st.Message)
}
}
}
func TestCookieFlagsRule_SameSiteNoneCaseInsensitive(t *testing.T) {
p := httpsProbe("a:443")
p.Cookies = []CookieInfo{{Name: "x", Secure: false, HttpOnly: true, SameSite: "none"}}