From c6d46413b6f8aeb870cae426c4a849f702e57b2d Mon Sep 17 00:00:00 2001 From: Oleksandr Nykytenko Date: Wed, 21 Oct 2026 12:46:16 +0300 Subject: [PATCH 01/12] Potential fix for code scanning alert no. 10: Uncontrolled command line Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> --- src/utils/hostServices/gitInvocation.cjs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/utils/hostServices/gitInvocation.cjs b/src/utils/hostServices/gitInvocation.cjs index 01fcfa7c..662a85f9 100644 --- a/src/utils/hostServices/gitInvocation.cjs +++ b/src/utils/hostServices/gitInvocation.cjs @@ -49,7 +49,8 @@ function helperTarget(args) { const isLfs=command[1].startsWith('git-lfs-');if(isLfs!==!!command[5])throw invalid('HELPER_ARGUMENTS_REJECTED'); const url=repo.startsWith('/')?`ssh://${username}@${host.includes(':')?'['+host+']':host}:${port}${repo}`:`${username}@${host}:${repo}`; const parsed=target(url);if(parsed.port!==port)throw invalid('HELPER_ARGUMENTS_REJECTED'); - return {url,service:command[1],direction:command[5],repository:repo,command:command[1]+" '"+repo+"'"+(command[5]?' '+command[5]:''),...parsed}; + const quotedRepo=repo.replace(/'/g, `'\"'\"'`); + return {url,service:command[1],direction:command[5],repository:repo,command:command[1]+" '"+quotedRepo+"'"+(command[5]?' '+command[5]:''),...parsed}; } async function childDirectory(root,relative) { if(!folder(relative))throw invalid('UNSAFE_REPOSITORY_CONFIG'); From 364a29f72e1083bca6c5dc7a98720156e20dd890 Mon Sep 17 00:00:00 2001 From: Oleksandr Nykytenko Date: Wed, 21 Oct 2026 13:03:58 +0300 Subject: [PATCH 02/12] Potential fix for code scanning alert no. 26: Incomplete multi-character sanitization Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> --- .../settings/panels/UpdatesPanel.jsx | 32 ++++++++++++------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/src/components/settings/panels/UpdatesPanel.jsx b/src/components/settings/panels/UpdatesPanel.jsx index b226a28e..a973e384 100644 --- a/src/components/settings/panels/UpdatesPanel.jsx +++ b/src/components/settings/panels/UpdatesPanel.jsx @@ -2,18 +2,26 @@ import React, {useCallback, useEffect, useState} from 'react'; import {Button, Callout, Card, HTMLSelect, H4, Intent, Spinner, Switch} from '@blueprintjs/core'; import Markdown from 'markdown-to-jsx'; -const formatReleaseNotes = value => String(value || '') - .replace(//g, '') - .replace(/\*\*Unsigned prerelease builds:\*\*\s*win-x64\.\s*macOS Gatekeeper and Windows SmartScreen may block these builds\./gi, 'Windows installers are published unsigned.') - .replace(/]*>\s*]*>([\s\S]*?)<\/summary>/gi, '\n### $1\n') - .replace(/<\/details\s*>/gi, '\n') - .replace(/<\/?summary\b[^>]*>/gi, '') - .replace(/</gi, '<') - .replace(/>/gi, '>') - .replace(/"/gi, '"') - .replace(/'|'/gi, "'") - .replace(/&/gi, '&') - .trim(); +const formatReleaseNotes = value => { + let notes = String(value || ''); + let previous; + do { + previous = notes; + notes = notes.replace(//g, ''); + } while (notes !== previous); + + return notes + .replace(/\*\*Unsigned prerelease builds:\*\*\s*win-x64\.\s*macOS Gatekeeper and Windows SmartScreen may block these builds\./gi, 'Windows installers are published unsigned.') + .replace(/]*>\s*]*>([\s\S]*?)<\/summary>/gi, '\n### $1\n') + .replace(/<\/details\s*>/gi, '\n') + .replace(/<\/?summary\b[^>]*>/gi, '') + .replace(/</gi, '<') + .replace(/>/gi, '>') + .replace(/"/gi, '"') + .replace(/'|'/gi, "'") + .replace(/&/gi, '&') + .trim(); +}; export const UpdatesPanel = ({checkOnOpen = false, checkRequestId}) => { const [checking, setChecking] = useState(false); From 2c588eb28a053501c224efaa839a12ce6dbb0f3b Mon Sep 17 00:00:00 2001 From: Oleksandr Nykytenko Date: Wed, 21 Oct 2026 13:07:11 +0300 Subject: [PATCH 03/12] Potential fix for code scanning alert no. 24: Inefficient regular expression Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> --- .../validation/unfencedWorkspaceSource.js | 36 ++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/src/utils/plugins/validation/unfencedWorkspaceSource.js b/src/utils/plugins/validation/unfencedWorkspaceSource.js index a3b623fe..db8a7084 100644 --- a/src/utils/plugins/validation/unfencedWorkspaceSource.js +++ b/src/utils/plugins/validation/unfencedWorkspaceSource.js @@ -1,5 +1,39 @@ import {parse} from '@babel/parser'; +function startsWithModuleKeywordAfterLeadingComments(text) { + let i = 0; + + while (i < text.length) { + while (i < text.length && /\s/.test(text[i])) i++; + + if (text.startsWith('//', i)) { + i += 2; + while (i < text.length && text[i] !== '\n') i++; + continue; + } + + if (text.startsWith('/*', i)) { + i += 2; + const end = text.indexOf('*/', i); + if (end === -1) return false; + i = end + 2; + continue; + } + + break; + } + + if (text.startsWith('import', i)) { + const next = text[i + 6]; + return !(next && /[A-Za-z0-9_$]/.test(next)); + } + if (text.startsWith('export', i)) { + const next = text[i + 6]; + return !(next && /[A-Za-z0-9_$]/.test(next)); + } + return false; +} + // Only recognize an entire completed module. Never extract a plausible code // fragment from prose, repair syntax, execute source, or infer its target path. export function isUnfencedWorkspaceModule(text, path) { @@ -20,7 +54,7 @@ export function inspectUnfencedWorkspaceModule(text, path) { } catch (error) { // Report syntax only for a recognizable module start, not arbitrary // prose. This is diagnostic evidence, never permission to apply it. - const moduleStart = /^\s*(?:(?:\/\/[^\n]*\n|\/\*[\s\S]*?\*\/)\s*)*(?:import|export)\b/.test(text); + const moduleStart = startsWithModuleKeywordAfterLeadingComments(text); return {valid: false, ...(moduleStart ? {syntaxError: String(error.message).slice(0, 500)} : {})}; } } From 6659e36e15dd9eaf029d00d4eb1250ce5f737ca6 Mon Sep 17 00:00:00 2001 From: Oleksandr Nykytenko Date: Wed, 21 Oct 2026 13:15:36 +0300 Subject: [PATCH 04/12] Potential fix for code scanning alert no. 23: Inefficient regular expression Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> --- src/ipc/ai/ai_chat_core.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ipc/ai/ai_chat_core.js b/src/ipc/ai/ai_chat_core.js index 18dc45ad..6737f3d4 100644 --- a/src/ipc/ai/ai_chat_core.js +++ b/src/ipc/ai/ai_chat_core.js @@ -2995,7 +2995,7 @@ async function toolFollowUp(llm, toolCalls) { const followUpResult = { content: sanitizeAssistantText( reply - .replace(/(?:\n|\r|^|\s)*sources used:?\s*[\s\S]*$/i, "") + .replace(/\s*sources used:?\s*[\s\S]*$/i, "") .trim() ), sources: uniqueSources, From 36b3e2b8b03a0b249d26c58491699db7cec16ae3 Mon Sep 17 00:00:00 2001 From: Oleksandr Nykytenko Date: Wed, 21 Oct 2026 13:19:51 +0300 Subject: [PATCH 05/12] Potential fix for code scanning alert no. 21: Inefficient regular expression Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> --- src/components/editor/utils/aiCodingAgentBuildOutput.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/editor/utils/aiCodingAgentBuildOutput.js b/src/components/editor/utils/aiCodingAgentBuildOutput.js index 75f00352..187e9737 100644 --- a/src/components/editor/utils/aiCodingAgentBuildOutput.js +++ b/src/components/editor/utils/aiCodingAgentBuildOutput.js @@ -51,7 +51,7 @@ function normalizeOutputMessage(message = "", workspaceFiles = []) { const pathRegexes = [ /\/[^\s:'"`)]+(?:\/[^\s:'"`)]+)*\.[A-Za-z0-9]+/g, - /[A-Za-z]:\\[^\s:'"`)]+(?:\\[^\s:'"`)]+)*\.[A-Za-z0-9]+/g, + /[A-Za-z]:\\[^\\/\s:'"`)]+(?:\\[^\\/\s:'"`)]+)*\.[A-Za-z0-9]+/g, ]; pathRegexes.forEach((regex) => { From ba0df0fb0dccd3e8cda70efe0b663522bac3cd8d Mon Sep 17 00:00:00 2001 From: Oleksandr Nykytenko Date: Wed, 21 Oct 2026 13:34:51 +0300 Subject: [PATCH 06/12] Potential fix for code scanning alert no. 19: Unvalidated dynamic method call Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> --- src/components/plugin/utils/pluginRequestBridge.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/components/plugin/utils/pluginRequestBridge.js b/src/components/plugin/utils/pluginRequestBridge.js index 1ae7b8ab..6785658f 100644 --- a/src/components/plugin/utils/pluginRequestBridge.js +++ b/src/components/plugin/utils/pluginRequestBridge.js @@ -16,6 +16,10 @@ export function createPluginRequestBridge(target = window) { const requestId = event.data.requestId; const resolve = pending.get(requestId); if (!resolve || !isValidPluginUiResponseEvent(event.data, requestId)) return; + if (typeof resolve !== 'function') { + pending.delete(requestId); + return; + } pending.delete(requestId); resolve(event.data.error ? {success: false, error: event.data.error} : event.data.content); }; From 11eb9703e40b8482453b4c465954a5dfdbc4cf5d Mon Sep 17 00:00:00 2001 From: Oleksandr Nykytenko Date: Wed, 21 Oct 2026 13:37:26 +0300 Subject: [PATCH 07/12] Potential fix for code scanning alert no. 18: Insecure randomness Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> --- src/utils/plugins/runtime/pluginHostAuth.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/utils/plugins/runtime/pluginHostAuth.js b/src/utils/plugins/runtime/pluginHostAuth.js index c44415de..a24d6114 100644 --- a/src/utils/plugins/runtime/pluginHostAuth.js +++ b/src/utils/plugins/runtime/pluginHostAuth.js @@ -1,3 +1,4 @@ +import {randomBytes} from "crypto"; import {isNetworkTargetAllowed} from "../security/networkScopeRegistry"; import { buildRuntimeSecurityPolicy, @@ -715,7 +716,7 @@ export async function handleHostAuthBrokerStartRequest(payload = {}, options = { const accountHint = toTrimmedString(payload?.accountHint); const accountId = accountHint || ""; const payloadSessionId = toTrimmedString(payload?.sessionId); - const sessionId = payloadSessionId || `sess_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`; + const sessionId = payloadSessionId || `sess_${Date.now()}_${randomBytes(8).toString("hex")}`; const raw = transportResult.raw; const credentials = extractSessionCredentials(raw, payload); const authTxnStore = getPluginAuthTxnStore(pluginId); From f8bd071b5e05a6af6b413792486a18c87f915ea9 Mon Sep 17 00:00:00 2001 From: Oleksandr Nykytenko Date: Wed, 21 Oct 2026 14:20:11 +0300 Subject: [PATCH 08/12] Potential fix for code scanning alert no. 5: Incomplete multi-character sanitization Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> --- .../plugins/authoring/liveUi/sdkComponentInsertion.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/utils/plugins/authoring/liveUi/sdkComponentInsertion.js b/src/utils/plugins/authoring/liveUi/sdkComponentInsertion.js index 8aaa6993..cc253bbf 100644 --- a/src/utils/plugins/authoring/liveUi/sdkComponentInsertion.js +++ b/src/utils/plugins/authoring/liveUi/sdkComponentInsertion.js @@ -39,7 +39,13 @@ export function describeSdkInsertions(files, elements, calls, html, contract, en } } } - const root = html.replace(/]*>[\s\S]*?<\/style\s*>/gi,'').trim(); + let root = html; + let previous; + do { + previous = root; + root = root.replace(/]*>[\s\S]*?<\/style\s*>/gi,''); + } while (root !== previous); + root = root.trim(); const rootId = /^]*\bdata-fdo-ui-id="([^"]+)"/i.exec(root)?.[1]; if (!rootId) return; const targets = insertionTargets(html, rootId, elements, calls); From f9eb8b3f0e7bac54448915e0be341344e30fb82c Mon Sep 17 00:00:00 2001 From: Oleksandr Nykytenko Date: Wed, 21 Oct 2026 14:22:10 +0300 Subject: [PATCH 09/12] Potential fix for code scanning alert no. 4: Incomplete string escaping or encoding Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> --- src/utils/plugins/authoring/liveUi/backendActions.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/plugins/authoring/liveUi/backendActions.js b/src/utils/plugins/authoring/liveUi/backendActions.js index bf43b066..76193b9b 100644 --- a/src/utils/plugins/authoring/liveUi/backendActions.js +++ b/src/utils/plugins/authoring/liveUi/backendActions.js @@ -141,7 +141,7 @@ export function planBackendResult(files,element,request) { if(outputs.length || oldRows.length) { if(marker !== config.marker || request.display !== mapping.display || changedOutputs) { let callback=backendFrontendSource(`[data-fdo-result="${marker}"]`,config.handler,config.text,config.inputMarker ? `[data-fdo-input="${config.inputMarker}"]` : '',config.inputTag,request.display,preset,outputs); - if(mapping.comments?.length) callback=callback.replace('{','{\n'+mapping.comments.join('\n')+'\n'); + if(mapping.comments?.length) callback=callback.replace('async () => {','async () => {\n'+mapping.comments.join('\n')+'\n'); operations.push({file:mapping.file,...mapping.callback,replacement:callback}); } } else { From e4990382dab850382ade4da37489643f8e653312 Mon Sep 17 00:00:00 2001 From: Oleksandr Nykytenko Date: Wed, 21 Oct 2026 14:23:18 +0300 Subject: [PATCH 10/12] Potential fix for code scanning alert no. 3: Double escaping or unescaping Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> --- src/utils/ai/assistant/externalReferenceKnowledge.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/utils/ai/assistant/externalReferenceKnowledge.js b/src/utils/ai/assistant/externalReferenceKnowledge.js index 6e74f08a..4ab1afad 100644 --- a/src/utils/ai/assistant/externalReferenceKnowledge.js +++ b/src/utils/ai/assistant/externalReferenceKnowledge.js @@ -10,11 +10,11 @@ function stripTags(html = "") { function decodeEntities(text = "") { return String(text || "") .replace(/ /g, " ") - .replace(/&/g, "&") .replace(/</g, "<") .replace(/>/g, ">") .replace(/"/g, '"') - .replace(/'/g, "'"); + .replace(/'/g, "'") + .replace(/&/g, "&"); } export function extractReferenceUrls(text = "") { From c330363fc3a00d7fa5f0fd1bf2e267e4a218323d Mon Sep 17 00:00:00 2001 From: Oleksandr Nykytenko Date: Wed, 21 Oct 2026 14:31:46 +0300 Subject: [PATCH 11/12] Potential fix for code scanning alert no. 2: Double escaping or unescaping Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> --- src/ipc/ai/tools/search_web.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ipc/ai/tools/search_web.js b/src/ipc/ai/tools/search_web.js index e93c41b7..f4fd4bb7 100644 --- a/src/ipc/ai/tools/search_web.js +++ b/src/ipc/ai/tools/search_web.js @@ -9,11 +9,11 @@ import {SEARCH_WEB_ECOSYSTEMS} from "./search_web_ecosystems.js"; function stripHtml(value = "") { return String(value) .replace(/<[^>]+>/g, " ") - .replace(/&/g, "&") .replace(/"/g, "\"") .replace(/'/g, "'") .replace(/</g, "<") .replace(/>/g, ">") + .replace(/&/g, "&") .replace(/\s+/g, " ") .trim(); } From e186e6fe6e662545c6839d9f067282da9f9dcde8 Mon Sep 17 00:00:00 2001 From: Oleksandr Nykytenko Date: Wed, 21 Oct 2026 14:34:04 +0300 Subject: [PATCH 12/12] Potential fix for code scanning alert no. 14: Improper code sanitization Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> --- .../plugins/authoring/liveUi/localActions.js | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/utils/plugins/authoring/liveUi/localActions.js b/src/utils/plugins/authoring/liveUi/localActions.js index 039bc975..25154bee 100644 --- a/src/utils/plugins/authoring/liveUi/localActions.js +++ b/src/utils/plugins/authoring/liveUi/localActions.js @@ -10,6 +10,21 @@ const markerPattern = /^visual-result-\d+$/; const inputMarkerPattern = /^visual-input-\d+$/; const resultTags = new Set(['p','pre','span','output']); const resultAttributes = new Set(['class','className','style','role','aria-label','aria-description','aria-live','title',markerName]); +const unsafeJsCharMap = { + '<': '\\u003C', + '>': '\\u003E', + '/': '\\u002F', + '\\': '\\\\', + '\b': '\\b', + '\f': '\\f', + '\n': '\\n', + '\r': '\\r', + '\t': '\\t', + '\0': '\\0', + '\u2028': '\\u2028', + '\u2029': '\\u2029' +}; +const escapeUnsafeChars = value => value.replace(/[<>\/\\\b\f\n\r\t\0\u2028\u2029]/g,char=>unsafeJsCharMap[char]); const literalFields = node => { if (node?.type !== 'ObjectExpression' || node.properties.some(p => p.type !== 'ObjectProperty' || p.computed)) return null; const entries = node.properties.map(p => [p.key.name ?? p.key.value,p]); @@ -121,9 +136,11 @@ export function planLocalAction(files,element,request) { while (occupied.includes('visual-result-'+number)) number++; const marker = target.marker || 'visual-result-'+number; const selector = `[${markerName}="${marker}"]`; + const safeSelectorLiteral = escapeUnsafeChars(JSON.stringify(selector)); + const safeTextLiteral = escapeUnsafeChars(JSON.stringify(request.text)); // No backend closure, tool execution or interpolation. The deployed handler // writes textContent, including for strings that resemble HTML or code. - const handler = `${JSON.stringify(name)}: () => { const target = document.querySelector(${JSON.stringify(selector)}); if (target) target.textContent = ${JSON.stringify(request.text)}; }, `; + const handler = `${JSON.stringify(name)}: () => { const target = document.querySelector(${safeSelectorLiteral}); if (target) target.textContent = ${safeTextLiteral}; }, `; const connection = planButtonAction(files,{...element,actionConnection:{...creation.connection,handlers:[{name,preventDefault:true}]}},{kind:'connect-action',handler:name}); const operations = connection.patches.map(({file,start,end,replacement})=>({file,start,end,replacement})); operations.push({file:'/index.ts',start:creation.handlerInsert,end:creation.handlerInsert,replacement:handler});