diff --git a/editors/vscode/client/PathValidator.ts b/editors/vscode/client/PathValidator.ts index a1e1f834a2bae..7ac1096ba7907 100644 --- a/editors/vscode/client/PathValidator.ts +++ b/editors/vscode/client/PathValidator.ts @@ -11,23 +11,37 @@ * Even though we are not using `shell: true`, it's a good practice to validate the input. */ export function validateSafeBinaryPath(binary: string): boolean { - // Check for path traversal - if (binary.includes('..')) { + // Check for path traversal (including Windows variants) + if (binary.includes('..') || binary.includes('.\\')) { return false; } // Check for malicious characters or patterns // These characters are never expected in a binary path. // If any of these characters are present, we consider the path unsafe. - const maliciousPatterns = ['$', '&', ';', '|', '`', '>', '<', '!']; + const maliciousPatterns = [ + // linux/macOS + '$', + '&', + ';', + '|', + '`', + '>', + '<', + '!', + // windows + '%', + '^', + ]; for (const pattern of maliciousPatterns) { if (binary.includes(pattern)) { return false; } } + // Check if the filename contains `oxc_language_server` // Malicious projects might try to point to a different binary. - if (!binary.includes('oxc_language_server')) { + if (!binary.replaceAll('\\', '/').toLowerCase().split('/').pop()?.includes('oxc_language_server')) { return false; } diff --git a/editors/vscode/tests/PathValidator.spec.ts b/editors/vscode/tests/PathValidator.spec.ts index 93d6a20388b82..f541896f3110d 100644 --- a/editors/vscode/tests/PathValidator.spec.ts +++ b/editors/vscode/tests/PathValidator.spec.ts @@ -9,11 +9,19 @@ suite('validateSafeBinaryPath', () => { strictEqual(validateSafeBinaryPath('/opt/oxc_language_server'), true); }); + test('should accept case variations of oxc_language_server', () => { + strictEqual(validateSafeBinaryPath('OXC_LANGUAGE_SERVER'), true); + strictEqual(validateSafeBinaryPath('OXC_LANGUAGE_SERVER.exe'), true); + strictEqual(validateSafeBinaryPath('/usr/local/bin/OXC_LANGUAGE_SERVER'), true); + strictEqual(validateSafeBinaryPath('C:\\Program Files\\OXC_LANGUAGE_SERVER.exe'), true); + }); + test('should reject paths with directory traversal', () => { strictEqual(validateSafeBinaryPath('../oxc_language_server'), false); strictEqual(validateSafeBinaryPath('../../oxc_language_server'), false); strictEqual(validateSafeBinaryPath('/usr/local/../bin/oxc_language_server'), false); strictEqual(validateSafeBinaryPath('..\\oxc_language_server'), false); + strictEqual(validateSafeBinaryPath('.\\oxc_language_server'), false); }); test('should reject paths with malicious characters', () => { @@ -24,6 +32,10 @@ suite('validateSafeBinaryPath', () => { strictEqual(validateSafeBinaryPath('oxc_language_server { @@ -32,5 +44,7 @@ suite('validateSafeBinaryPath', () => { strictEqual(validateSafeBinaryPath(''), false); strictEqual(validateSafeBinaryPath('oxc_language'), false); strictEqual(validateSafeBinaryPath('language_server'), false); + strictEqual(validateSafeBinaryPath('/oxc_language_server/malicious'), false); + strictEqual(validateSafeBinaryPath('C:\\oxc_language_server\\evil.exe'), false); }); });