fix(web): state the expected shape when dropping a CSP source (#2064)
`approveCspSources` warned "dropping unsafe CSP source", which states a security verdict the check never makes: `SAFE_CSP_SOURCE` screens each entry for injection safety only, and deliberately does not bound how broad a grant is (`resourceDomains: ["*"]` passes). The four fields are origin lists, so the real cause of a drop is almost always that the entry isn't an origin — a CSP keyword such as `'unsafe-eval'` has no field in the contract to be requested through. Reading it as a safety verdict is what sent #2012 chasing an XSS regression that wasn't one. The message now names the field the entry came from (so an app declaring several lists can tell which one was bad) and states the shape expected, with no claim about the value's safety. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UL9retfvAXRgvi6EWk4SY4 Signed-off-by: cliffhall <cliff@futurescale.com>
This commit is contained in:
parent
a92a73003b
commit
268bfa1085
1 changed files with 42 additions and 6 deletions
|
|
@ -41,11 +41,11 @@ const CSP_KEYS = exhaustiveCspKeys([
|
|||
|
||||
/**
|
||||
* Filter an app-supplied {@link McpUiResourceCsp} down to the entries the host
|
||||
* will actually enforce. Unsafe values are dropped (and warned), and the
|
||||
* resulting object contains only keys with at least one accepted source. The
|
||||
* return value is what the host echoes back to the view via
|
||||
* `hostCapabilities.sandbox.csp` so the app sees what was granted, not what it
|
||||
* asked for.
|
||||
* will actually enforce. Entries that don't parse as a source expression are
|
||||
* dropped (and warned), and the resulting object contains only keys with at
|
||||
* least one accepted source. The return value is what the host echoes back to
|
||||
* the view via `hostCapabilities.sandbox.csp` so the app sees what was granted,
|
||||
* not what it asked for.
|
||||
*
|
||||
* NOTE: this screens each source for *injection safety* only — it does NOT
|
||||
* bound the *breadth* of a grant. A bare `*` (and a scheme-wildcard host) is a
|
||||
|
|
@ -56,6 +56,14 @@ const CSP_KEYS = exhaustiveCspKeys([
|
|||
* ambient credentials and nothing to exfiltrate beyond what the app already
|
||||
* received; "approved" therefore means "cannot break out of the meta
|
||||
* attribute," not "restrictive."
|
||||
*
|
||||
* The drop warning is worded accordingly: it names the field the entry came
|
||||
* from and states the shape expected, and makes no claim about the *safety* of
|
||||
* the value. These four fields are origin lists, so the usual cause of a drop
|
||||
* is an entry that simply isn't an origin — a CSP keyword such as
|
||||
* `'unsafe-eval'` has no field in the contract to be requested through. Saying
|
||||
* "unsafe" instead read as a security verdict this check never makes, and sent
|
||||
* #2012 chasing an XSS regression that wasn't one (#2064).
|
||||
*/
|
||||
export function approveCspSources(
|
||||
csp: McpUiResourceCsp | undefined,
|
||||
|
|
@ -70,7 +78,12 @@ export function approveCspSources(
|
|||
if (typeof entry === "string" && SAFE_CSP_SOURCE.test(entry)) {
|
||||
accepted.push(entry);
|
||||
} else {
|
||||
console.warn("[mcp-app sandbox] dropping unsafe CSP source:", entry);
|
||||
console.warn(
|
||||
`[mcp-app sandbox] dropping "${key}" entry (expected an origin such ` +
|
||||
`as https://example.com or https://*.example.com, a scheme such as ` +
|
||||
`data:, or *):`,
|
||||
entry,
|
||||
);
|
||||
}
|
||||
}
|
||||
if (accepted.length > 0) approved[key] = accepted;
|
||||
|
|
|
|||
Loading…
Reference in a new issue