diff --git a/moli-benchmark/wpt-cross-current/failed-cases.txt b/moli-benchmark/wpt-cross-current/failed-cases.txt index 08122ebeb8..654bd34b8f 100644 --- a/moli-benchmark/wpt-cross-current/failed-cases.txt +++ b/moli-benchmark/wpt-cross-current/failed-cases.txt @@ -3280,7 +3280,6 @@ svg/types/scripted/SVGLength-viewport.html trusted-types/ServiceWorkerContainer-register-from-DedicatedWorker.https.html trusted-types/ServiceWorkerContainer-register-from-ServiceWorker.https.html trusted-types/ServiceWorkerContainer-register-from-SharedWorker.https.html -trusted-types/should-trusted-type-policy-creation-be-blocked-by-csp-002.html trusted-types/trusted-types-createHTMLDocument.html trusted-types/trusted-types-report-only.html trusted-types/trusted-types-reporting-for-DedicatedWorker-ServiceWorkerContainer-register.https.html diff --git a/moli-benchmark/wpt-cross-current/passed-cases.txt b/moli-benchmark/wpt-cross-current/passed-cases.txt index 23003cfb52..4612c922da 100644 --- a/moli-benchmark/wpt-cross-current/passed-cases.txt +++ b/moli-benchmark/wpt-cross-current/passed-cases.txt @@ -8437,6 +8437,7 @@ trusted-types/should-sink-type-mismatch-violation-be-blocked-by-csp-001.html trusted-types/should-sink-type-mismatch-violation-be-blocked-by-csp-002-worker.html trusted-types/should-sink-type-mismatch-violation-be-blocked-by-csp-003.html trusted-types/should-trusted-type-policy-creation-be-blocked-by-csp-001.html +trusted-types/should-trusted-type-policy-creation-be-blocked-by-csp-002.html trusted-types/should-trusted-type-policy-creation-be-blocked-by-csp-003.html trusted-types/should-trusted-type-policy-creation-be-blocked-by-csp-004-worker.html trusted-types/should-trusted-type-policy-creation-be-blocked-by-csp-005.html diff --git a/moli-renderer-v8/src/content_security_policy.rs b/moli-renderer-v8/src/content_security_policy.rs index 63a85df8cd..0d84e24673 100644 --- a/moli-renderer-v8/src/content_security_policy.rs +++ b/moli-renderer-v8/src/content_security_policy.rs @@ -1199,6 +1199,9 @@ fn policy_allows_trusted_type_policy_name( source == "*" || (!source.is_empty() && source == policy_name + // Only tt-policy-name tokens can whitelist a literal name. + // The policy API itself accepts arbitrary strings, including + // under a wildcard, so do not validate policy_name globally. && source.bytes().all(|byte| { byte.is_ascii_alphanumeric() || matches!(byte, b'-' | b'#' | b'=' | b'_' | b'/' | b'@' | b'.' | b'%') @@ -1207,7 +1210,7 @@ fn policy_allows_trusted_type_policy_name( let duplicate_is_allowed = !is_duplicate || sources .iter() - .any(|source| csp_keyword_eq(source.trim(), "allow-duplicates")); + .any(|source| csp_keyword_eq(source, "allow-duplicates")); name_is_allowed && duplicate_is_allowed } @@ -3477,26 +3480,31 @@ mod tests { assert!(policy_allows_trusted_type_policy_name( &format!("trusted-types {name}"), name, - false + false, )); } assert!(policy_allows_trusted_type_policy_name( "trusted-types valid policy*name", "valid", - false + false, )); assert!(!policy_allows_trusted_type_policy_name( "trusted-types valid policy*name", "policy*name", - false + false, )); for wildcard in ["\u{000b}*", "*\u{000b}", "policy*"] { assert!(!policy_allows_trusted_type_policy_name( &format!("trusted-types {wildcard}"), "valid", - false + false, )); } + assert!(!policy_allows_trusted_type_policy_name( + "trusted-types valid \u{000b}'allow-duplicates'", + "valid", + true, + )); } #[test] @@ -3512,6 +3520,16 @@ mod tests { for policy in ["", "trusted-types *"] { assert!(policy_allows_trusted_type_policy_name(policy, name, false)); } + assert!(!policy_allows_trusted_type_policy_name( + "trusted-types *", + name, + true, + )); + assert!(policy_allows_trusted_type_policy_name( + "trusted-types * 'allow-duplicates'", + name, + true, + )); } } diff --git a/moli-renderer-v8/src/script_vm/tests/browser_api/trusted_types.rs b/moli-renderer-v8/src/script_vm/tests/browser_api/trusted_types.rs index 8c2b29c7f7..78be2351d4 100644 --- a/moli-renderer-v8/src/script_vm/tests/browser_api/trusted_types.rs +++ b/moli-renderer-v8/src/script_vm/tests/browser_api/trusted_types.rs @@ -433,6 +433,80 @@ fn trusted_type_policy_creation_reports_name_and_duplicate_csp_violations() { ); } +#[test] +fn trusted_types_csp_name_grammar_preserves_enforcement_and_report_only_delivery() { + let policy = "trusted-types valid policy*name policy$name policy?name policy!name"; + let names = [ + "valid", + "policy*name", + "policy$name", + "policy?name", + "policy!name", + "política", + "", + ]; + for enforce in [false, true] { + let mut vm = new_storage_test_vm("https://trusted-types-name-grammar.test/"); + if enforce { + vm.set_response_content_security_policies(&[ + policy.to_owned(), + "trusted-types ignored política".to_owned(), + ]); + } + vm.set_response_content_security_report_only_policies(&[ + policy.to_owned(), + "trusted-types ignored política".to_owned(), + ]); + let actual = vm.eval(r#" +globalThis.policyNameGrammarReports = []; +document.addEventListener('securitypolicyviolation', event => { + policyNameGrammarReports.push([event.sample, event.originalPolicy, event.disposition]); +}); +JSON.stringify(['valid', 'policy*name', 'policy$name', 'policy?name', 'policy!name', 'política', ''].map(name => { + try { return trustedTypes.createPolicy(name).name; } + catch (error) { return error instanceof TypeError ? 'TypeError' : error.name; } +})); +"#).unwrap(); + assert_eq!( + serde_json::from_str::(&actual).unwrap(), + if enforce { + serde_json::json!([ + "valid", + "TypeError", + "TypeError", + "TypeError", + "TypeError", + "TypeError", + "TypeError" + ]) + } else { + serde_json::json!(names) + }, + ); + assert_eq!(vm.eval("policyNameGrammarReports.length").unwrap(), "0"); + let expected = names[1..] + .iter() + .flat_map(|name| { + let mut reports = Vec::new(); + if enforce { + reports.push(serde_json::json!([name, policy, "enforce"])); + } + reports.push(serde_json::json!([name, policy, "report"])); + reports + }) + .collect::>(); + assert_eq!( + drain_pre_domcontentloaded_non_script_page_tasks_for_test(&mut vm), + expected.len(), + ); + let actual = vm.eval("JSON.stringify(policyNameGrammarReports)").unwrap(); + assert_eq!( + serde_json::from_str::(&actual).unwrap(), + serde_json::json!(expected), + ); + } +} + #[test] fn trusted_type_policy_creation_reports_every_violated_policy() { let enforced = [