diff --git a/patches/backported-patches.json b/patches/backported-patches.json index e8afbd4..86cdeba 100644 --- a/patches/backported-patches.json +++ b/patches/backported-patches.json @@ -88,5 +88,17 @@ "patch_path": "N/A", "link": "https://github.com/microsoft/vscode/commit/bc2d56c6f8da22a4bd31f741fcb034208770f158", "note": "Notebook Restricted-Mode bypass via mermaid render. Upstream vulnerable file extensions/mermaid-markdown-features/preview-src/notebook/index.ts (the 'temp.innerHTML = result' sink and renderMermaidBlocksInElement) does not exist in this branch's shipped source. The only mermaid extension here, mermaid-chat-features, renders diagrams via escapeHtmlText() into a
and uses textContent (chat-webview-src/mermaidWebview.ts) inside a sandboxed webview with strict nonce CSP - no innerHTML of untrusted content. The markdown-language-features notebook renderer already sanitizes untrusted HTML with DOMPurify. No equivalent vulnerable innerHTML/insertAdjacentHTML sink for untrusted render output exists."
+ },
+ {
+ "finding_id": "CVE-2026-70334",
+ "affected_versions": "< 1.136.2",
+ "patch_path": "patches/common/fix-config-nested-restricted-settings.diff",
+ "link": "https://github.com/microsoft/vscode/commit/0684cb5905a3f23156f45a28135326e09310ff4d"
+ },
+ {
+ "finding_id": "GHSA-q2f8-hh8x-wpc2",
+ "affected_versions": "< 1.136.2",
+ "patch_path": "patches/common/fix-config-nested-restricted-settings.diff",
+ "link": "https://github.com/microsoft/vscode/commit/0684cb5905a3f23156f45a28135326e09310ff4d"
}
]
diff --git a/patches/common/fix-config-nested-restricted-settings.diff b/patches/common/fix-config-nested-restricted-settings.diff
new file mode 100644
index 0000000..1b65e8c
--- /dev/null
+++ b/patches/common/fix-config-nested-restricted-settings.diff
@@ -0,0 +1,77 @@
+From: Sandeep Somavarapu
+Subject: Filter restricted settings in nested configuration objects
+Origin: upstream, https://github.com/microsoft/vscode/commit/0684cb5905a3f23156f45a28135326e09310ff4d
+Bug: GHSA-q2f8-hh8x-wpc2
+
+ConfigurationModelParser only checked top-level keys against the
+configuration registry. Walk nested objects and check each setting by its
+effective dotted path. Remove when Code-OSS is updated to >= 1.136.2.
+Index: code-editor-src/src/vs/platform/configuration/common/configurationModels.ts
+===================================================================
+--- code-editor-src.orig/src/vs/platform/configuration/common/configurationModels.ts
++++ code-editor-src/src/vs/platform/configuration/common/configurationModels.ts
+@@ -441,12 +441,11 @@ export class ConfigurationModelParser {
+ hasExcludedProperties = hasExcludedProperties || result.hasExcludedProperties;
+ restricted.push(...result.restricted);
+ } else {
+- const propertySchema = configurationProperties[key];
+- if (propertySchema?.restricted) {
+- restricted.push(key);
+- }
+- if (this.shouldInclude(key, propertySchema, excludedConfigurationProperties, options)) {
+- raw[key] = properties[key];
++ const result = this.filterProperty(key, properties[key], configurationProperties, excludedConfigurationProperties, options);
++ restricted.push(...result.restricted);
++ hasExcludedProperties = hasExcludedProperties || result.hasExcludedProperties;
++ if (result.included) {
++ raw[key] = result.value;
+ } else {
+ hasExcludedProperties = true;
+ }
+@@ -455,6 +454,46 @@ export class ConfigurationModelParser {
+ return { raw, restricted, hasExcludedProperties };
+ }
+
++ private filterProperty(path: string, value: unknown, configurationProperties: IStringDictionary, excludedConfigurationProperties: IStringDictionary, options: ConfigurationParseOptions): { included: boolean; value: unknown; restricted: string[]; hasExcludedProperties: boolean } {
++ const propertySchema = configurationProperties[path];
++ if (propertySchema) {
++ return { included: this.shouldInclude(path, propertySchema, excludedConfigurationProperties, options), value, restricted: propertySchema.restricted ? [path] : [], hasExcludedProperties: false };
++ }
++ if (!types.isObject(value) || Array.isArray(value)) {
++ return { included: this.shouldInclude(path, propertySchema, excludedConfigurationProperties, options), value, restricted: [], hasExcludedProperties: false };
++ }
++ // Excluded properties can themselves be object-typed (e.g. `mcp.enterpriseManagedAuth.idp`), so treat them as a leaf too.
++ if (excludedConfigurationProperties[path]) {
++ return { included: this.shouldInclude(path, propertySchema, excludedConfigurationProperties, options), value, restricted: [], hasExcludedProperties: false };
++ }
++ // If the whole object is explicitly excluded, do not recurse into its children.
++ if (options.exclude?.includes(path)) {
++ return { included: false, value, restricted: [], hasExcludedProperties: false };
++ }
++ const keys = Object.keys(value);
++ if (keys.length === 0) {
++ return { included: this.shouldInclude(path, propertySchema, excludedConfigurationProperties, options), value, restricted: [], hasExcludedProperties: false };
++ }
++ const nested: IStringDictionary = {};
++ const restricted: string[] = [];
++ let included = false;
++ let hasExcludedProperties = false;
++ for (const key of keys) {
++ const result = this.filterProperty(`${path}.${key}`, (value as IStringDictionary)[key], configurationProperties, excludedConfigurationProperties, options);
++ if (result.restricted.length) {
++ restricted.push(...result.restricted);
++ }
++ hasExcludedProperties = hasExcludedProperties || result.hasExcludedProperties;
++ if (result.included) {
++ nested[key] = result.value;
++ included = true;
++ } else {
++ hasExcludedProperties = true;
++ }
++ }
++ return { included, value: nested, restricted, hasExcludedProperties };
++ }
++
+ private shouldInclude(key: string, propertySchema: IConfigurationPropertySchema | undefined, excludedConfigurationProperties: IStringDictionary, options: ConfigurationParseOptions): boolean {
+ if (options.exclude?.includes(key)) {
+ return false;
diff --git a/patches/sagemaker.series b/patches/sagemaker.series
index ccfc8bf..b25c373 100644
--- a/patches/sagemaker.series
+++ b/patches/sagemaker.series
@@ -72,3 +72,4 @@ common/finding-override-undici.diff
common/finding-override-form-data.diff
common/finding-override-tar.diff
common/fix-copilot-debug-override-user-scope.diff
+common/fix-config-nested-restricted-settings.diff
diff --git a/patches/web-embedded-with-terminal.series b/patches/web-embedded-with-terminal.series
index 4ea4488..4e1bd06 100644
--- a/patches/web-embedded-with-terminal.series
+++ b/patches/web-embedded-with-terminal.series
@@ -68,3 +68,4 @@ common/fix-remote-hosts-loopback.diff
common/finding-override-undici.diff
common/finding-override-form-data.diff
common/fix-copilot-debug-override-user-scope.diff
+common/fix-config-nested-restricted-settings.diff
diff --git a/patches/web-embedded.series b/patches/web-embedded.series
index 721ea56..b3fa141 100644
--- a/patches/web-embedded.series
+++ b/patches/web-embedded.series
@@ -71,3 +71,4 @@ common/fix-remote-hosts-loopback.diff
common/finding-override-undici.diff
common/finding-override-form-data.diff
common/fix-copilot-debug-override-user-scope.diff
+common/fix-config-nested-restricted-settings.diff
diff --git a/patches/web-server.series b/patches/web-server.series
index 34bdd22..a41164f 100644
--- a/patches/web-server.series
+++ b/patches/web-server.series
@@ -50,3 +50,4 @@ common/fix-remote-hosts-loopback.diff
common/finding-override-undici.diff
common/finding-override-form-data.diff
common/fix-copilot-debug-override-user-scope.diff
+common/fix-config-nested-restricted-settings.diff