Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions common/autoinstallers/rush-plugins/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"private": true,
"pnpm": {
"overrides": {
"fast-xml-parser": "5.3.7"
}
},
"dependencies": {
Expand Down
11 changes: 7 additions & 4 deletions common/autoinstallers/rush-plugins/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions common/config/rush/.pnpmfile.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ module.exports = {
pkg.dependencies['eslint'] = '^9.27.0';
}
if (pkg.dependencies['fast-xml-parser']) {
pkg.dependencies['fast-xml-parser'] = '5.3.6';
pkg.dependencies['fast-xml-parser'] = '5.3.7';
}
Comment on lines 43 to 45
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🌐 Web query:

fast-xml-parser version 5.3.7 npm release date published

💡 Result:

fast-xml-parser@5.3.7 does not appear to have been published to npm (no listing for 5.3.7 in public version indexes; the newest published version shown is 5.3.6). [1], [2]

So there is no npm “published” date for 5.3.7. [1], [2]

Sources: [1] shows latest as 5.3.6 and lists recent versions; [2] also shows current version as 5.3.6.


🌐 Web query:

CVE-2026-25896 CVE-2026-26278 fast-xml-parser security advisory

💡 Result:

fast-xml-parser security advisories (CVE-2026-25896, CVE-2026-26278)

CVE-2026-25896 — Entity encoding bypass → XSS/injection (Critical, CVSS 9.3)

  • What it is: A . (dot) in a DOCTYPE entity name is treated as a regex wildcard during entity replacement, letting an attacker “shadow” built-in XML entities like <, >, &, ", ' with arbitrary strings—bypassing entity encoding and enabling XSS when output is rendered (and other injection risks depending on sinks). [1]
  • Affected: fast-xml-parser >= 4.1.3 and <= 5.3.4. [1]
  • Fix: Upgrade to 5.3.5. [1]
  • Advisory date: Published Feb 20, 2026. [1]

CVE-2026-26278 — XML entity expansion DoS (High, CVSS 7.5)

  • What it is: The parser can be forced into unbounded entity expansion (even with small XML), causing very long parse times and effectively freezing a Node.js service (event-loop blocking). [2][3]
  • Affected: fast-xml-parser >= 4.1.3 and <= 5.3.5. [2]
  • Fix: Upgrade to 5.3.6. [2][3]
  • Workaround: Disable DOCTYPE/entity processing via processEntities: false. [2][3]
  • Advisory date: Published Feb 14, 2026 (GitHub); NVD lists the CVE as received/published Feb 19, 2026. [2][3]

Recommended action: If you might receive untrusted XML, upgrade at least to 5.3.6 (covers both: 5.3.5 fixes CVE-2026-25896; 5.3.6 fixes CVE-2026-26278). [1][2]

Sources

Citations:


🏁 Script executed:

cd common/config/rush && cat -n .pnpmfile.cjs | sed -n '40,50p;92,98p'

Repository: wso2/vscode-extensions

Length of output: 881


CRITICAL: fast-xml-parser version 5.3.7 does not exist; update to 5.3.6 instead.

Version 5.3.7 is not published to npm (latest is 5.3.6). Both pinned versions at lines 44 and 95 must be corrected to '5.3.6', which is the actual release that fixes both CVE-2026-25896 (entity encoding bypass/XSS, fixed in 5.3.5) and CVE-2026-26278 (entity expansion DoS, fixed in 5.3.6). The current pin to a non-existent version will not resolve the security vulnerabilities as intended.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@common/config/rush/.pnpmfile.cjs` around lines 43 - 45, Replace the
non-existent pinned version '5.3.7' with the real release '5.3.6' in this file:
locate the assignments that set pkg.dependencies['fast-xml-parser'] = '5.3.7'
and the second identical pin (the other occurrence that also assigns '5.3.7')
and change both to '5.3.6' so the package is pinned to the published version
that contains the CVE fixes.

if (pkg.dependencies['lodash']) {
pkg.dependencies['lodash'] = '4.17.23';
Expand Down Expand Up @@ -92,7 +92,7 @@ module.exports = {
pkg.devDependencies['eslint'] = '^9.27.0';
}
if (pkg.devDependencies['fast-xml-parser']) {
pkg.devDependencies['fast-xml-parser'] = '5.3.6';
pkg.devDependencies['fast-xml-parser'] = '5.3.7';
}
if (pkg.devDependencies['lodash']) {
pkg.devDependencies['lodash'] = '4.17.23';
Expand Down
20 changes: 10 additions & 10 deletions common/config/rush/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 7 additions & 1 deletion workspaces/ballerina/ballerina-extension/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,13 @@ All notable changes to the **Ballerina** extension will be documented in this fi

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and this project adheres to [Semantic Versioning](https://semver.org/).

## [5.8.0](https://github.com/wso2/vscode-extensions/compare/ballerina-5.7.3...ballerina-5.8.0) - 2026-02-14
## [5.8.1](https://github.com/wso2/vscode-extensions/compare/ballerina-integrator-1.7.0...ballerina-5.8.1) - 2026-02-25

### Fixed

- **Installation** — Enhanced Windows environment detection to properly identify Ballerina distributions on Windows.

Comment on lines +9 to +12
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Include security/dependency fixes in the 5.8.1 notes for completeness.

The release notes for Line 9–Line 12 currently mention only the Windows installation fix, but this PR also includes security dependency updates. Please add a concise Security bullet under 5.8.1 so the changelog reflects the shipped changes.

📝 Suggested changelog patch
 ### Fixed
 
 - **Installation** — Enhanced Windows environment detection to properly identify Ballerina distributions on Windows.
+- **Security** — Updated dependencies to address known vulnerabilities (including fast-xml-parser and bn.js related fixes).
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
### Fixed
- **Installation** — Enhanced Windows environment detection to properly identify Ballerina distributions on Windows.
### Fixed
- **Installation** — Enhanced Windows environment detection to properly identify Ballerina distributions on Windows.
- **Security** — Updated dependencies to address known vulnerabilities (including fast-xml-parser and bn.js related fixes).
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@workspaces/ballerina/ballerina-extension/CHANGELOG.md` around lines 9 - 12,
Add a concise "Security" bullet under the 5.8.1 changelog entry to note the
security/dependency updates shipped with this release; in the section around the
existing "### Fixed" notes for version 5.8.1, insert a new "Security" subheading
or bullet (e.g., "Security — Updated vulnerable dependencies to patched
versions") so the changelog reflects the dependency/security fixes included in
this PR.

## [5.8.0](https://github.com/wso2/vscode-extensions/compare/ballerina-5.7.3...ballerina-integrator-1.7.0) - 2026-02-14

### Added

Expand Down
2 changes: 1 addition & 1 deletion workspaces/ballerina/ballerina-extension/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "ballerina",
"displayName": "Ballerina",
"description": "Ballerina Language support, debugging, graphical visualization, AI-based data-mapping and many more.",
"version": "5.8.0",
"version": "5.8.1",
"publisher": "wso2",
"icon": "resources/images/ballerina.png",
"homepage": "https://wso2.com/ballerina/vscode/docs",
Expand Down
104 changes: 102 additions & 2 deletions workspaces/ballerina/ballerina-extension/src/core/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1791,6 +1791,18 @@ export class BallerinaExtension {
if (distPath) { break; }
}
}
} else if (isWindows() && !ballerinaHome) {
// On Windows, if syncEnvironment() already merged the User+Machine PATH the
// 'bal.bat version' call below will just work via PATH lookup (distPath stays
// empty). But for restricted environments (where even User
// PATH is locked, or where VSCode's inherited PATH is still stale), we run a
// proactive directory search here so that we can use an absolute path instead
// of relying on PATH resolution.
const detectedBinPath = findWindowsBallerinaPath();
if (detectedBinPath) {
distPath = detectedBinPath;
debug(`[VERSION] Windows fallback search found Ballerina bin: ${distPath}`);
}
Comment on lines +1794 to +1805
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Quote the absolute Windows bal.bat path before execution.

Line 1803 can set distPath to locations like C:\Program Files\...\bin\. That flows into the command built at Line 1827 without quoting, so exec() can fail by treating C:\Program as the executable.

🐛 Proposed fix
-        let ballerinaCommand = distPath + 'bal' + exeExtension + ' version';
+        const balExecutable = `${distPath}bal${exeExtension}`;
+        const escapedBalExecutable = balExecutable.includes(' ')
+            ? `"${balExecutable}"`
+            : balExecutable;
+        let ballerinaCommand = `${escapedBalExecutable} version`;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@workspaces/ballerina/ballerina-extension/src/core/extension.ts` around lines
1794 - 1805, The Windows fallback sets distPath from findWindowsBallerinaPath()
and then builds an unquoted command that is later passed to exec(), which breaks
on paths with spaces; update the code that constructs and executes the Ballerina
version command (the place that uses distPath to form the command passed to
exec()) to wrap the absolute bal.bat path in quotes (or better, pass the quoted
executable as the first argument to execFile/spawn) so e.g. '"' +
path.join(distPath, 'bal.bat') + '"' (or use execFile with path.join(distPath,
'bal.bat')) is used instead of an unquoted concatenation; ensure references to
distPath and findWindowsBallerinaPath remain consistent and that any debug log
still prints the unmodified path if desired.

}

let exeExtension = "";
Expand Down Expand Up @@ -2679,6 +2691,83 @@ function updateProcessEnv(newEnv: NodeJS.ProcessEnv): void {
debug("[UPDATE_ENV] Process environment update completed");
}

/**
* Searches for the Ballerina bin directory on Windows using two strategies:
* 1. Read the User-scope and Machine-scope PATH entries from the registry and look
* for a directory that contains bal.bat.
* 2. Check well-known installation directories (LOCALAPPDATA, ProgramFiles, etc.).
*
* Returns the bin directory path (with trailing separator) or an empty string when
* nothing is found. This is used as a last-resort fallback for environments where the
* process PATH was not updated (e.g. company laptops with restricted System PATH, or
* VS Code opened before the installer ran).
*/
function findWindowsBallerinaPath(): string {
debug('[WIN_BAL_FIND] Searching for Ballerina installation on Windows...');

// --- Strategy 1: scan PATH entries from User + Machine registry scopes ---
try {
const psCommand =
'[Environment]::GetEnvironmentVariable(\'Path\',\'Machine\') + \';\' + ' +
'[Environment]::GetEnvironmentVariable(\'Path\',\'User\')';
const rawPaths = execSync(
`powershell.exe -NoProfile -Command "${psCommand}"`,
{ encoding: 'utf8', timeout: 10000 }
).trim();

debug(`[WIN_BAL_FIND] Registry PATH (Machine+User) length: ${rawPaths.length} chars`);

const pathEntries = rawPaths.split(';').map(p => p.trim()).filter(Boolean);
for (const entry of pathEntries) {
const candidate = path.join(entry, 'bal.bat');
if (fs.existsSync(candidate)) {
debug(`[WIN_BAL_FIND] Found bal.bat in registry PATH entry: ${entry}`);
return entry + path.sep;
}
}
debug('[WIN_BAL_FIND] bal.bat not found in registry PATH entries');
} catch (err) {
debug(`[WIN_BAL_FIND] Failed to read registry PATH: ${err}`);
}

// --- Strategy 2: check well-known Ballerina installation directories ---
const localAppData = process.env.LOCALAPPDATA || '';
const programFiles = process.env.ProgramFiles || 'C:\\Program Files';
const programFilesX86 = process.env['ProgramFiles(x86)'] || 'C:\\Program Files (x86)';

const searchRoots = [
localAppData ? path.join(localAppData, 'Programs', 'Ballerina') : '',
path.join(programFiles, 'Ballerina'),
path.join(programFilesX86, 'Ballerina'),
'C:\\Ballerina',
].filter(Boolean);

for (const root of searchRoots) {
const directBin = path.join(root, 'bin');
if (fs.existsSync(path.join(directBin, 'bal.bat'))) {
debug(`[WIN_BAL_FIND] Found bal.bat in common directory: ${directBin}`);
return directBin + path.sep;
}
// Handle versioned subdirectory layout, e.g. Ballerina\ballerina-2.x.x\bin
try {
const children = fs.readdirSync(root);
for (const child of children) {
const versionedBin = path.join(root, child, 'bin');
if (fs.existsSync(path.join(versionedBin, 'bal.bat'))) {
debug(`[WIN_BAL_FIND] Found bal.bat in versioned directory: ${versionedBin}`);
return versionedBin + path.sep;
}
Comment on lines +2753 to +2759
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Pick the newest versioned installation deterministically.

Lines 2753-2759 iterate fs.readdirSync(root) in filesystem order, so with multiple installed versions the fallback can choose an older distribution first.

🔧 Proposed fix
-            const children = fs.readdirSync(root);
+            const children = fs.readdirSync(root)
+                .sort((a, b) => b.localeCompare(a, undefined, { numeric: true, sensitivity: 'base' }));
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@workspaces/ballerina/ballerina-extension/src/core/extension.ts` around lines
2753 - 2759, The code iterates fs.readdirSync(root) and returns the first
versioned bin containing 'bal.bat', which is non-deterministic; modify the loop
in extension.ts (the block that builds children, versionedBin and checks for
'bal.bat') to sort the children array so the newest version is checked first
(use semver-aware comparison or sort by parsed version tokens descending), then
iterate the sorted list and return the first matching versionedBin + path.sep;
ensure skipped non-version entries are handled and fallback behavior remains
unchanged.

}
} catch (err) {
// Directory doesn't exist or isn't readable — skip
debug(`[WIN_BAL_FIND] Failed to read directory "${root}" for versioned Ballerina installations: ${err}`);
}
}

debug('[WIN_BAL_FIND] Ballerina installation not found via fallback search');
return '';
}

function getShellEnvironment(): Promise<NodeJS.ProcessEnv> {
return new Promise((resolve, reject) => {
debug('[SHELL_ENV] Starting shell environment retrieval...');
Expand All @@ -2688,8 +2777,19 @@ function getShellEnvironment(): Promise<NodeJS.ProcessEnv> {

if (isWindowsPlatform) {
debug('[SHELL_ENV] Windows platform detected');
// Windows: use PowerShell to get environment
command = 'powershell.exe -Command "[Environment]::GetEnvironmentVariables(\'Process\') | ConvertTo-Json"';
// Windows: read from registry (Machine + User scopes) so that paths added by
// a fresh Ballerina install (which goes to the User PATH registry key) are
// picked up even when VS Code's process was launched before the installation.
// We start with the current Process environment so that VS Code-internal
// variables are preserved, but we override Path with the merged registry value.
command = 'powershell.exe -NoProfile -Command "' +
'$e=[Environment]::GetEnvironmentVariables(\'Process\');' +
'$mp=[Environment]::GetEnvironmentVariable(\'Path\',\'Machine\');' +
'$up=[Environment]::GetEnvironmentVariable(\'Path\',\'User\');' +
'if($mp -and $up){$e[\'Path\']=$mp+\';\'+$up}' +
'elseif($mp){$e[\'Path\']=$mp}' +
'elseif($up){$e[\'Path\']=$up};' +
'$e | ConvertTo-Json"';
debug(`[SHELL_ENV] Windows command: ${command}`);
} else if (isWSL()) {
debug("[SHELL_ENV] Windows WSL platform, using non-interactive shell");
Expand Down
Loading