Make sure to escape cspSource

Good practice

Also makes sure we don't include full file uris in the csp
This commit is contained in:
Matt Bierner
2025-05-22 00:01:01 -07:00
parent 1d7ad01f17
commit 73f244c82b
2 changed files with 14 additions and 10 deletions

View File

@@ -94,7 +94,7 @@ export class MdDocumentRenderer {
<html style="${escapeAttribute(this._getSettingsOverrideStyles(config))}"> <html style="${escapeAttribute(this._getSettingsOverrideStyles(config))}">
<head> <head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8"> <meta http-equiv="Content-type" content="text/html;charset=UTF-8">
${csp} <meta http-equiv="Content-Security-Policy" content="${escapeAttribute(csp)}">
<meta id="vscode-markdown-preview-data" <meta id="vscode-markdown-preview-data"
data-settings="${escapeAttribute(JSON.stringify(initialData))}" data-settings="${escapeAttribute(JSON.stringify(initialData))}"
data-strings="${escapeAttribute(JSON.stringify(previewStrings))}" data-strings="${escapeAttribute(JSON.stringify(previewStrings))}"
@@ -230,20 +230,20 @@ export class MdDocumentRenderer {
resource: vscode.Uri, resource: vscode.Uri,
nonce: string nonce: string
): string { ): string {
const rule = provider.cspSource; const rule = provider.cspSource.split(';')[0];
switch (this._cspArbiter.getSecurityLevelForResource(resource)) { switch (this._cspArbiter.getSecurityLevelForResource(resource)) {
case MarkdownPreviewSecurityLevel.AllowInsecureContent: case MarkdownPreviewSecurityLevel.AllowInsecureContent:
return `<meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src 'self' ${rule} http: https: data:; media-src 'self' ${rule} http: https: data:; script-src 'nonce-${nonce}'; style-src 'self' ${rule} 'unsafe-inline' http: https: data:; font-src 'self' ${rule} http: https: data:;">`; return `default-src 'none'; img-src 'self' ${rule} http: https: data:; media-src 'self' ${rule} http: https: data:; script-src 'nonce-${nonce}'; style-src 'self' ${rule} 'unsafe-inline' http: https: data:; font-src 'self' ${rule} http: https: data:;`;
case MarkdownPreviewSecurityLevel.AllowInsecureLocalContent: case MarkdownPreviewSecurityLevel.AllowInsecureLocalContent:
return `<meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src 'self' ${rule} https: data: http://localhost:* http://127.0.0.1:*; media-src 'self' ${rule} https: data: http://localhost:* http://127.0.0.1:*; script-src 'nonce-${nonce}'; style-src 'self' ${rule} 'unsafe-inline' https: data: http://localhost:* http://127.0.0.1:*; font-src 'self' ${rule} https: data: http://localhost:* http://127.0.0.1:*;">`; return `default-src 'none'; img-src 'self' ${rule} https: data: http://localhost:* http://127.0.0.1:*; media-src 'self' ${rule} https: data: http://localhost:* http://127.0.0.1:*; script-src 'nonce-${nonce}'; style-src 'self' ${rule} 'unsafe-inline' https: data: http://localhost:* http://127.0.0.1:*; font-src 'self' ${rule} https: data: http://localhost:* http://127.0.0.1:*;`;
case MarkdownPreviewSecurityLevel.AllowScriptsAndAllContent: case MarkdownPreviewSecurityLevel.AllowScriptsAndAllContent:
return '<meta http-equiv="Content-Security-Policy" content="">'; return ``;
case MarkdownPreviewSecurityLevel.Strict: case MarkdownPreviewSecurityLevel.Strict:
default: default:
return `<meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src 'self' ${rule} https: data:; media-src 'self' ${rule} https: data:; script-src 'nonce-${nonce}'; style-src 'self' ${rule} 'unsafe-inline' https: data:; font-src 'self' ${rule} https: data:;">`; return `default-src 'none'; img-src 'self' ${rule} https: data:; media-src 'self' ${rule} https: data:; script-src 'nonce-${nonce}'; style-src 'self' ${rule} 'unsafe-inline' https: data:; font-src 'self' ${rule} https: data:;`;
} }
} }
} }

View File

@@ -430,7 +430,11 @@ class MarkdownPreview extends Disposable implements WebviewResourceProvider {
get cspSource() { get cspSource() {
return [ return [
this._webviewPanel.webview.cspSource, this._webviewPanel.webview.cspSource,
...this._contributionProvider.contributions.previewResourceRoots.map(root => {
// On web, we also need to allow loading of resources from contributed extensions
...this._contributionProvider.contributions.previewResourceRoots
.filter(root => root.scheme === 'http' || root.scheme === 'https')
.map(root => {
const dirRoot = root.path.endsWith('/') ? root : root.with({ path: root.path + '/' }); const dirRoot = root.path.endsWith('/') ? root : root.with({ path: root.path + '/' });
return dirRoot.toString(); return dirRoot.toString();
}), }),