From 308c2d281f38fcf688f16eb15d6c00c94b55a5d1 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 8 Jan 2026 21:44:32 +0000 Subject: [PATCH 1/2] Initial plan From 9de9f927a36b445af35a5b543b8ccf4b5da93866 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 8 Jan 2026 21:55:01 +0000 Subject: [PATCH 2/2] Add URI scheme validation for components from untrusted sources Co-authored-by: bryanchen-d <41454397+bryanchen-d@users.noreply.github.com> --- src/vs/base/common/uri.ts | 7 ++-- src/vs/base/test/common/uri.test.ts | 56 +++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 3 deletions(-) diff --git a/src/vs/base/common/uri.ts b/src/vs/base/common/uri.ts index ac2ae962d7269..5e321de5d7a8a 100644 --- a/src/vs/base/common/uri.ts +++ b/src/vs/base/common/uri.ts @@ -162,9 +162,10 @@ export class URI implements UriComponents { this.path = schemeOrData.path || _empty; this.query = schemeOrData.query || _empty; this.fragment = schemeOrData.fragment || _empty; - // no validation because it's this URI - // that creates uri components. - // _validateUri(this); + // Validate when constructing from components. While internal code that creates + // uri components should be correct, components may come from untrusted sources + // (e.g., IPC) and need validation to prevent errors. + _validateUri(this); } else { this.scheme = _schemeFix(schemeOrData, _strict); this.authority = authority || _empty; diff --git a/src/vs/base/test/common/uri.test.ts b/src/vs/base/test/common/uri.test.ts index e2f22d32ef8c8..5e3fe3cef6782 100644 --- a/src/vs/base/test/common/uri.test.ts +++ b/src/vs/base/test/common/uri.test.ts @@ -645,5 +645,61 @@ suite('URI', () => { } }); + test('URI.revive should validate scheme from untrusted components', () => { + // Test that URI.revive throws an error when scheme contains illegal characters + const invalidComponents = { + scheme: 'invalid scheme', // space is illegal in scheme + authority: 'example.com', + path: '/path', + query: '', + fragment: '' + }; + + assert.throws(() => { + URI.revive(invalidComponents); + }, /Scheme contains illegal characters/); + }); + + test('URI.revive should validate various invalid schemes', () => { + const invalidSchemes = [ + 'invalid scheme', // contains space + 'invalid@scheme', // contains @ + 'invalid/scheme', // contains / + 'invalid:scheme', // contains : + 'invalid#scheme', // contains # + '123invalid', // starts with digit + '+invalid', // starts with + + '-invalid', // starts with - + '.invalid', // starts with . + ]; + + for (const scheme of invalidSchemes) { + assert.throws(() => { + URI.revive({ scheme, authority: '', path: '', query: '', fragment: '' }); + }, /Scheme contains illegal characters/, `Should throw for scheme: ${scheme}`); + } + }); + + test('URI.revive should allow valid schemes', () => { + const validSchemes = [ + 'file', + 'http', + 'https', + 'ftp', + 'myscheme', + 'my-scheme', + 'my.scheme', + 'my+scheme', + 'a123', + 'MyScheme', + ]; + + for (const scheme of validSchemes) { + assert.doesNotThrow(() => { + URI.revive({ scheme, authority: '', path: '', query: '', fragment: '' }); + }, `Should not throw for valid scheme: ${scheme}`); + } + }); + });