The mismatch today
Cursor’s workbench.html says:
workbench.html
Lines 58-87
require-trusted-types-for
'script'
;
trusted-types
amdLoader
...
anysphereUiPolicy
...
;
But some workbench code still does things like:
new Function(...) / dynamic eval
element.innerHTML = plainString
trustedTypes.createPolicy(...) without a singleton guard
With require-trusted-types-for 'script' on, 'unsafe-eval' in script-src is not enough. You also need either:
trusted-types-eval in CSP, or
Every script sink to go through a createScript policy, or
Stop using Function / raw-string DOM sinks entirely
Right now Cursor has (1) enforcement ON, (2) partially implemented, (3) not done everywhere.
Fix type A — CSP one-liner (broad, fast, less ideal)
File: out/vs/code/electron-sandbox/workbench/workbench.html
script-src
'self'
'unsafe-eval'
trusted-types-eval
blob:
;
Effect: new Function("...") and eval("...") work again with plain strings even under Trusted Types.
Tradeoff: Weakens the exact protection require-trusted-types-for is trying to provide for code compilation sinks. Fine as a temporary unblock; not a great long-term security posture.
Fix type B — Add createScript policies (proper fix for Function)
Most Cursor/VS Code policies only define createHTML or createScriptURL. Your failing case needs createScript.
Example of what they already do for HTML (good pattern):
// anysphereUiPolicy — only createHTML today
window.trustedTypes.createPolicy("anysphereUiPolicy", {
createHTML: (html) => html
});
What they’d add for code that compiles strings:
window.trustedTypes.createPolicy("anysphereUiPolicy", {
createHTML: (html) => html,
createScript: (script) => script,
});
And at call sites that currently do raw compilation:
const fn = new Function("return " + expr);
const policy = getOrCreatePolicy("anysphereUiPolicy", {
createHTML: s => s,
createScript: s => s,
});
const body = policy.createScript("return " + expr);
const fn = globalThis.eval(body); // or a shared trustedFunction(...args, body) helper
VS Code already has a central helper (createTrustedTypesPolicy in vs/base/browser/trustedTypes.js) — the diff on Cursor’s side is route new code through it instead of ad-hoc createPolicy / raw sinks.
Angular/VS Code-style helper they’d ideally centralize:
function trustedFunction(...args: string[]): Function {
const policy = createTrustedTypesPolicy('cursorScript', {
createScript: (s) => s,
});
const paramList = args.slice(0, -1);
const body = args[args.length - 1];
const script = policy!.createScript(body);
const fn = globalThis.eval(script) as Function;
fn.toString = () => body;
return fn.bind(globalThis);
}
That’s the “real” fix for the error you reproduced manually.
Fix type C — Stop unsafe fallbacks (subtle bug)
In the bundle, Cursor UI code looks like:
// If policy exists, use it; else write raw string anyway
Tqr ? n.innerHTML = Tqr.createHTML(e) : n.innerHTML = e
Under enforcement, that else branch always throws if policy creation failed — and silently “worked” before TT was strict.
Tqr ? n.innerHTML = Tqr.createHTML(e) : n.innerHTML = e
if (!Tqr) throw new Error("anysphereUiPolicy unavailable under Trusted Types enforcement");
n.innerHTML = Tqr.createHTML(e);
Same idea anywhere they fallback to raw strings “just in case.”
Fix type D — Duplicate policy names (separate known crash)
Forum reports: Policy with name "tokenizeToString" already exists.
They already guard anysphereUiPolicy with a singleton:
if (window.__anysphereUiTrustedTypesPolicy) return window.__anysphereUiTrustedTypesPolicy;
window.__anysphereUiTrustedTypesPolicy = window.trustedTypes.createPolicy(...);
The diff is to apply that everywhere policies are created, especially tokenizeToString (listed twice in CSP already):
let _tokenizePolicy;
function getTokenizePolicy() {
return trustedTypes.createPolicy('tokenizeToString', ...); // throws on 2nd call
if (_tokenizePolicy) return _tokenizePolicy;
_tokenizePolicy = createTrustedTypesPolicy('tokenizeToString', { createHTML: s => s });
return _tokenizePolicy;
}
Or use 'allow-duplicates' in CSP — worse than singletons.
Fix type E — New Cursor features need CSP allowlist entries
When Background Composer / Cloud Agent / Zod schemas init, any new policy name must be added to workbench.html:
trusted-types
...
shikiWorkerFactory
cursorComposerScript
backgroundComposerPolicy
;
Missing name → createPolicy() throws before any code runs.
What the actual “diff” looks like in practice
For Cursor engineers, it’s not one line — it’s a matrix:
Violation you saw Cursor-side fix
Function constructor / TrustedScript
Add trusted-types-eval or createScript policy + trustedFunction helper
TrustedHTML on innerHTML
Use existing createHTML policies; remove raw-string fallbacks
createPolicy throws “already exists”
Singleton cache per policy name
createPolicy throws “not allowed”
Add policy name to trusted-types in workbench.html
Third-party lib uses Function internally
Wrap at boundary, swap lib, or trusted-types-eval
Your manual test points to the Function / createScript bucket — very likely in newer Cursor modules (composer, background agent, Zod validation) that VS Code’s upstream workbench didn’t have when the CSP was designed.
What they should not do
Assume 'unsafe-eval' fixes it (you proved it doesn’t)
Disable Trusted Types entirely (big security regression vs VS Code baseline)
Patch only in DevTools/console (user workaround, not a product fix)
Minimal fix vs correct fix
Minimal unblock:
Correct fix:
Add shared trustedFunction / createScript policy
Fix composer/background-agent call sites to use it
Singleton all createPolicy calls
Keep require-trusted-types-for 'script' without trusted-types-eval
If you grab __cspViolations[0].source after reload, we can map it to which of A–E applies first in your build — but from your new Function test, the top item on their fix list is almost certainly B (+ maybe E for a new policy name).
Composer 2.5 proposed the fix ![]()