Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Trusted Types: Improve testing of samples in violation reports. #50238

Merged
merged 3 commits into from
Jan 23, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,20 @@
<body>
<script>
promise_test(async t => {
const policyName = 'SomeName';
let violation = await trusted_type_violation_for(TypeError, _ =>
window.trustedTypes.createPolicy('SomeName', { createHTML: s => s } )
window.trustedTypes.createPolicy(policyName, { createHTML: s => s } )
);
assert_true(violation.originalPolicy.includes("trusted-types 'none'"));
assert_equals(violation.sample, clipSampleIfNeeded(policyName));
}, "Cannot create policy with name 'SomeName' - policy creation throws");

promise_test(async t => {
const policyName = 'default';
let violation = await trusted_type_violation_for(TypeError, _ =>
window.trustedTypes.createPolicy('default', { createHTML: s => s } )
window.trustedTypes.createPolicy(policyName, { createHTML: s => s } )
);
assert_true(violation.originalPolicy.includes("trusted-types 'none'"));
assert_equals(violation.sample, clipSampleIfNeeded(policyName));
}, "Cannot create policy with name 'default' - policy creation throws");
</script>
Original file line number Diff line number Diff line change
Expand Up @@ -24,20 +24,24 @@

// Non-allowed names test
promise_test(async t => {
const policyName = 'SomeOtherName';
let violation = await trusted_type_violation_for(TypeError, _ =>
window.trustedTypes.createPolicy('SomeOtherName', { createHTML: s => s } )
window.trustedTypes.createPolicy(policyName, { createHTML: s => s } )
);
assert_true(violation.originalPolicy.includes("trusted-types SomeName JustOneMoreName AnotherName"));
assert_equals(violation.sample, clipSampleIfNeeded(policyName));
}, "Non-allowed name policy creation throws.");

// Duplicate names test
promise_test(async t => {
let policy = window.trustedTypes.createPolicy('AnotherName', { createHTML: s => s } );
assert_equals(policy.name, 'AnotherName');
const policyName = 'AnotherName';
let policy = window.trustedTypes.createPolicy(policyName, { createHTML: s => s } );
assert_equals(policy.name, policyName);

let violation = await trusted_type_violation_for(TypeError, _ =>
window.trustedTypes.createPolicy('AnotherName', { createHTML: s => s } )
window.trustedTypes.createPolicy(policyName, { createHTML: s => s } )
);
assert_true(violation.originalPolicy.includes("trusted-types SomeName JustOneMoreName AnotherName"));
assert_equals(violation.sample, clipSampleIfNeeded(policyName));
}, "Duplicate name policy creation throws.");
</script>
11 changes: 11 additions & 0 deletions trusted-types/support/csp-violations.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,14 @@ async function trusted_type_violation_without_exception_for(fn) {
assert_equals(exception, null, "no exception thrown");
return violations[0];
}

function clipSampleIfNeeded(sample) {
const clippedSampleLength = 40;

// Clipping is a bit ambiguous when the sample contains surrogate pairs, so
// avoid that in our tests for now.
// https://github.com/w3c/trusted-types/issues/577
assert_equals(sample.match(/[\uD800-\uDBFF][\uDC00-\uDFFF]/), null);

return sample.substring(0, clippedSampleLength);
}
13 changes: 9 additions & 4 deletions trusted-types/trusted-types-eval-reporting-no-unsafe-eval.html
Original file line number Diff line number Diff line change
Expand Up @@ -34,31 +34,36 @@
window.script_run_beacon = 'never_overwritten';

promise_test(async t => {
const input = 'script_run_beacon="should not run"';
let violation = await trusted_type_violation_for(EvalError, _ =>
eval('script_run_beacon="should not run"')
eval(input)
);
assert_true(violation.originalPolicy.includes("require-trusted-types-for 'script'"));
assert_equals(violation.sample, `eval|${clipSampleIfNeeded(input)}`);
assert_equals(script_run_beacon, 'never_overwritten');
}, "Trusted Type violation report: evaluating a string violates both script-src and trusted-types.");

promise_test(async t => {
const input = 'script_run_beacon="i ran"';
let violation = await trusted_type_violation_for(EvalError, _ =>
eval(scriptyPolicy.createScript('script_run_beacon="i ran"'))
eval(scriptyPolicy.createScript(input))
);
assert_equals(violation.effectiveDirective, "script-src");
assert_equals(violation.sample, clipSampleIfNeeded(input));
assert_not_equals(script_run_beacon, 'i ran'); // Code did not run.
assert_equals(script_run_beacon, 'never_overwritten');
}, "Trusted Type violation report: evaluating a Trusted Script violates script-src.");

promise_test(async t => {
const input = 'script_run_beacon="should not run"';
trustedTypes.createPolicy('default', {
createScript: s => s,
}, true);
let violation = await trusted_type_violation_for(EvalError, _ =>
eval('script_run_beacon="should not run"') // script-src will block.
eval(input) // script-src will block.
);
assert_equals(violation.effectiveDirective, "script-src");
assert_true(violation.sample.includes("should not run"));
assert_equals(violation.sample, clipSampleIfNeeded(input));
assert_not_equals(script_run_beacon, 'should not run'); // Code did not run.
assert_equals(script_run_beacon, 'never_overwritten');
}, "Trusted Type violation report: script-src restrictions apply after the default policy runs.");
Expand Down
4 changes: 3 additions & 1 deletion trusted-types/trusted-types-eval-reporting-report-only.html
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,12 @@
window.script_run_beacon = 'vanilla';

promise_test(async t => {
const input = 'script_run_beacon="report-only-does-not-stop"';
let violation = await trusted_type_violation_without_exception_for(_ =>
eval('script_run_beacon="report-only-does-not-stop"')
eval(input)
);
assert_true(violation.originalPolicy.includes("require-trusted-types-for 'script'"));
assert_equals(violation.sample, `eval|${clipSampleIfNeeded(input)}`);
assert_equals(script_run_beacon, 'report-only-does-not-stop');
}, "Trusted Type violation report: evaluating a string.");

Expand Down
4 changes: 3 additions & 1 deletion trusted-types/trusted-types-eval-reporting.html
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,13 @@
const scriptyPolicy = trustedTypes.createPolicy('allowEval', a_policy);

promise_test(async t => {
const input = 'beacon="should not run"';
let beacon = 'never_overwritten';
let violation = await trusted_type_violation_for(EvalError, _ =>
eval('beacon="should not run"')
eval(input)
);
assert_true(violation.originalPolicy.includes("require-trusted-types-for 'script'"));
assert_equals(violation.sample, `eval|${clipSampleIfNeeded(input)}`);
assert_equals(beacon, 'never_overwritten');
}, "Trusted Type violation report: evaluating a string.");

Expand Down
79 changes: 43 additions & 36 deletions trusted-types/trusted-types-reporting.html
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,6 @@

const url = "" + document.location;

// TODO(vogelheim): The current set of tests allows for more variance in the
// sample reports than the current spec draft does. Once the spec has
// been finalized, we should clamp this down to check byte-for-byte
// against the values mandated by the spec.

// A sample policy we use to test trustedTypes.createPolicy behaviour.
const id = x => x;
const a_policy = {
Expand All @@ -47,26 +42,30 @@
};

promise_test(async t => {
const policyName = "three";
let {violations, exception} =
await trusted_type_violations_and_exception_for(_ =>
trustedTypes.createPolicy("three", a_policy)
);
assert_equals(violations.length, 2);
assert_true(violations[0].originalPolicy.includes("trusted-types one"));
assert_equals(violations[0].sample, clipSampleIfNeeded(policyName));
assert_equals(violations[0].blockedURI, "trusted-types-policy");
assert_true(violations[1].originalPolicy.includes("trusted-types two"));
assert_true(violations[1].sample.includes("three"));
assert_equals(violations[1].sample, clipSampleIfNeeded(policyName));
assert_equals(violations[1].blockedURI, "trusted-types-policy");
assert_true(exception instanceof TypeError);
}, "Trusted Type violation report: creating a forbidden policy.");

promise_test(async t => {
const policyName = "two";
let {violations, exception} =
await trusted_type_violations_and_exception_for(_ =>
trustedTypes.createPolicy("two", a_policy)
trustedTypes.createPolicy(policyName, a_policy)
);
assert_equals(violations.length, 1);
assert_true(violations[0].originalPolicy.includes("trusted-types one"));
assert_true(violations[0].sample.includes("two"));
assert_equals(violations[0].sample, clipSampleIfNeeded(policyName));
assert_equals(violations[0].blockedURI, "trusted-types-policy");
assert_true(exception instanceof TypeError);
}, "Trusted Type violation report: creating a report-only-forbidden policy.");
Expand All @@ -75,15 +74,14 @@
let policy_one = null;

promise_test(async t => {
let {violations, exception} =
const policyName = "one";
let violation =
await trusted_type_violation_without_exception_for(_ =>
policy_one = trustedTypes.createPolicy("one", a_policy)
policy_one = trustedTypes.createPolicy(policyName, a_policy)
);
assert_equals(violations.length, 1);
assert_true(violations[0].originalPolicy.includes("trusted-types two"));
assert_true(violations[0].sample.includes("one"));
assert_equals(violations[0].blockedURI, "trusted-types-policy");
assert_equals(exception, null);
assert_true(violation.originalPolicy.includes("trusted-types two"));
assert_equals(violation.sample, clipSampleIfNeeded(policyName));
assert_equals(violation.blockedURI, "trusted-types-policy");
}, "Trusted Type violation report: creating a forbidden-but-not-reported policy.");

promise_test(async t => {
Expand Down Expand Up @@ -121,75 +119,83 @@
}, "Trusted Type violation report: assign trusted HTML to html; no report");

promise_test(async t => {
const input = "abc";
let violation = await trusted_type_violation_for(TypeError, _ =>
document.getElementById("div").innerHTML = "abc"
document.getElementById("div").innerHTML = input
);
assert_true(violation.originalPolicy.includes("require-trusted-types-for 'script'"));
assert_equals(violation.blockedURI, "trusted-types-sink");
assert_true(violation.sample.includes("Element innerHTML|abc"));
assert_equals(violation.sample, `Element innerHTML|${clipSampleIfNeeded(input)}`);
}, "Trusted Type violation report: sample for innerHTML assignment");

promise_test(async t => {
const input = "1+2;";
let violation = await trusted_type_violation_for(TypeError, _ =>
document.getElementById("script").text = "abc"
document.getElementById("script").text = input
);
assert_true(violation.originalPolicy.includes("require-trusted-types-for 'script'"));
assert_equals(violation.blockedURI, "trusted-types-sink");
assert_true(violation.sample.includes("HTMLScriptElement text|abc"));
assert_equals(violation.sample, `HTMLScriptElement text|${clipSampleIfNeeded(input)}`);
}, "Trusted Type violation report: sample for text assignment");

promise_test(async t => {
const input = "about:blank";
let violation = await trusted_type_violation_for(TypeError, _ =>
document.getElementById("script").src = ""
document.getElementById("script").src = input
);
assert_true(violation.originalPolicy.includes("require-trusted-types-for 'script'"));
assert_equals(violation.blockedURI, "trusted-types-sink");
assert_true(violation.sample.includes("HTMLScriptElement src"));
assert_equals(violation.sample, `HTMLScriptElement src|${clipSampleIfNeeded(input)}`);
}, "Trusted Type violation report: sample for script.src assignment");

promise_test(async t => {
const input = "2+2;";
let violation = await trusted_type_violation_for(TypeError, _ =>
document.getElementById("script").innerText = "2+2;"
);
assert_true(violation.originalPolicy.includes("require-trusted-types-for 'script'"));
assert_equals(violation.blockedURI, "trusted-types-sink");
assert_true(violation.sample.includes("Element innerText|2+2"));
assert_equals(violation.sample, `HTMLScriptElement innerText|${clipSampleIfNeeded(input)}`);
}, "Trusted Type violation report: sample for script innerText assignment");

promise_test(async t => {
const input = "about:blank";
let violation = await trusted_type_violation_for(TypeError, _ =>
document.getElementById("svgscript").href.baseVal = ""
document.getElementById("svgscript").href.baseVal = input
);
assert_true(violation.originalPolicy.includes("require-trusted-types-for 'script'"));
assert_equals(violation.blockedURI, "trusted-types-sink");
assert_true(violation.sample.includes("SVGScriptElement href"));
assert_equals(violation.sample, `SVGScriptElement href|${clipSampleIfNeeded(input)}`);
}, "Trusted Type violation report: sample for SVGScriptElement href assignment");

promise_test(async t => {
const input = "about:blank";
let violation = await trusted_type_violation_for(TypeError, _ =>
document.getElementById("svgscript").setAttribute('href', "test")
document.getElementById("svgscript").setAttribute('href', input)
);
assert_true(violation.originalPolicy.includes("require-trusted-types-for 'script'"));
assert_equals(violation.blockedURI, "trusted-types-sink");
assert_true(violation.sample.includes("SVGScriptElement href"));
assert_equals(violation.sample, `SVGScriptElement href|${clipSampleIfNeeded(input)}`);
}, "Trusted Type violation report: sample for SVGScriptElement href assignment by setAttribute");

promise_test(async t => {
const input = "2+3";
let violation = await trusted_type_violation_for(TypeError, _ =>
document.getElementById("svgscript").insertBefore(document.createTextNode("Hello"), null)
document.getElementById("svgscript").insertBefore(document.createTextNode(input), null)
);
assert_true(violation.originalPolicy.includes("require-trusted-types-for 'script'"));
assert_equals(violation.blockedURI, "trusted-types-sink");
assert_true(violation.sample.includes("SVGScriptElement text"));
assert_equals(violation.sample, `SVGScriptElement text|${clipSampleIfNeeded(input)}`);
}, "Trusted Type violation report: sample for SVGScriptElement text assignment");

promise_test(async t => {
const input = "2+2";
let violation = await trusted_type_violation_for(EvalError, _ =>
eval("2+2")
eval(input)
);
assert_true(violation.originalPolicy.includes("require-trusted-types-for 'script'"));
assert_equals(violation.blockedURI, "trusted-types-sink");
assert_true(violation.sample.includes("eval|2+2"));
assert_equals(violation.sample, `eval|${clipSampleIfNeeded(input)}`);
}, "Trusted Type violation report: sample for eval");

promise_test(async t => {
Expand All @@ -201,8 +207,7 @@
);
assert_true(violation.originalPolicy.includes("require-trusted-types-for 'script'"));
assert_equals(violation.blockedURI, "trusted-types-sink");
assert_true(violation.sample.includes("HTMLScriptElement innerText|abbb"));
assert_less_than(violation.sample.length, 150);
assert_equals(violation.sample, `HTMLScriptElement innerText|${clipSampleIfNeeded(value)}`);
}, "Trusted Type violation report: large values should be handled sanely.");

// Test reporting for Custom Elements (where supported). The report should
Expand All @@ -213,22 +218,24 @@
customElements.define("custom-script", CustomScript, { extends: "script" });

promise_test(async t => {
const input = "about:blank";
let violation = await trusted_type_violation_for(TypeError, _ =>
document.getElementById("customscript").src = "abc"
document.getElementById("customscript").src = input
);
assert_true(violation.originalPolicy.includes("require-trusted-types-for 'script'"));
assert_equals(violation.blockedURI, "trusted-types-sink");
assert_true(violation.sample.includes("HTMLScriptElement src|abc"));
assert_equals(violation.sample, `HTMLScriptElement src|${clipSampleIfNeeded(input)}`);
}, "Trusted Type violation report: sample for custom element assignment");
}

promise_test(async t => {
const input = "about:blank";
let violation = await trusted_type_violation_for(TypeError, _ =>
new Worker("blabla")
new Worker(input)
);
assert_true(violation.originalPolicy.includes("require-trusted-types-for 'script'"));
assert_equals(violation.blockedURI, "trusted-types-sink");
assert_true(violation.sample.includes("Worker constructor|"));
assert_equals(violation.sample, `Worker constructor|${clipSampleIfNeeded(input)}`);
}, "Trusted Type violation report: Worker constructor");

</script>
Expand Down
14 changes: 10 additions & 4 deletions trusted-types/trusted-types-source-file-path.html
Original file line number Diff line number Diff line change
Expand Up @@ -33,32 +33,38 @@
}

promise_test(async t => {
const input = "'test'";
let violation = await trusted_type_violation_for(TypeError, _ =>
document.getElementById("to-be-modified").innerHTML = "'test'"
document.getElementById("to-be-modified").innerHTML = input
);
assert_equals(violation.sourceFile, location.href)
assert_equals(violation.sourceFile, location.href);
assert_equals(violation.sample, `Element innerHTML|${clipSampleIfNeeded(input)}`);
}, "same-document script")

promise_test(async t => {
const input = "'test'";
let script_origin = get_host_info().HTTP_ORIGIN;
let script_src = script_origin +
"/trusted-types/support/set-inner-html.js";
let script = await futureScript(script_src);
let violation = await trusted_type_violation_for(TypeError, _ =>
setInnerHtml(toBeModified, "'test'")
setInnerHtml(toBeModified, input)
);
assert_equals(violation.sourceFile, script_src);
assert_equals(violation.sample, `Element innerHTML|${clipSampleIfNeeded(input)}`);
}, "same-origin script")

promise_test(async t => {
const input = "'test'";
let script_origin = get_host_info().HTTP_REMOTE_ORIGIN;
let script_src = script_origin +
"/trusted-types/support/set-inner-html.js";
let script = await futureScript(script_src);
let violation = await trusted_type_violation_for(TypeError, _ =>
setInnerHtml(toBeModified, "'test'")
setInnerHtml(toBeModified, input)
);
assert_equals(violation.sourceFile, script_src);
assert_equals(violation.sample, `Element innerHTML|${clipSampleIfNeeded(input)}`);
}, "cross-origin script")

// TODO(arthursonzogni): Check what happens with redirects. Do we report the
Expand Down
Loading
Loading