diff --git a/src/browser/Clipboard.test.ts b/src/browser/Clipboard.test.ts index aa7bdabdd1..2028504ec8 100644 --- a/src/browser/Clipboard.test.ts +++ b/src/browser/Clipboard.test.ts @@ -29,4 +29,14 @@ describe('evaluatePastedTextProcessing', () => { assert.equal(unbracketedText, 'foo bar'); assert.equal(bracketedText, '\x1b[200~foo bar\x1b[201~'); }); + + it('should escape embedded escape sequences in pasted text only when bracketed', () => { + const ESC_SYMBOL = '\u241b'; + const pastedText = '\x1b[201~foo\x1b[200~bar'; + const unbracketedText = Clipboard.bracketTextForPaste(pastedText, false); + const bracketedText = Clipboard.bracketTextForPaste(pastedText, true); + + assert.equal(unbracketedText, pastedText, 'non bracketed paste should remain unchanged'); + assert.equal(bracketedText, `\x1b[200~${ESC_SYMBOL}[201~foo${ESC_SYMBOL}[200~bar\x1b[201~`); + }); }); diff --git a/src/browser/Clipboard.ts b/src/browser/Clipboard.ts index ec85b5836d..aaf8a48e41 100644 --- a/src/browser/Clipboard.ts +++ b/src/browser/Clipboard.ts @@ -19,10 +19,13 @@ export function prepareTextForTerminal(text: string): string { * @param text The pasted text to bracket */ export function bracketTextForPaste(text: string, bracketedPasteMode: boolean): string { - if (bracketedPasteMode) { - return '\x1b[200~' + text + '\x1b[201~'; + if (!bracketedPasteMode) { + return text; } - return text; + // Sanitize pasted text to prevent injected escape sequences (e.g. exiting bracketed paste) + // by replacing ESC (\x1b) with its visible representation U+241B (␛). + const sanitizedText = text.replace(/\x1b/g, '\u241b'); + return `\x1b[200~${sanitizedText}\x1b[201~`; } /** diff --git a/src/browser/services/CoreBrowserService.ts b/src/browser/services/CoreBrowserService.ts index 5052de6d28..658caaeb1c 100644 --- a/src/browser/services/CoreBrowserService.ts +++ b/src/browser/services/CoreBrowserService.ts @@ -13,7 +13,7 @@ export class CoreBrowserService extends Disposable implements ICoreBrowserServic private _isFocused = false; private _cachedIsFocused: boolean | undefined = undefined; - private _screenDprMonitor = this._register(new ScreenDprMonitor(this._window)); + private _screenDprMonitor: ScreenDprMonitor; private readonly _onDprChange = this._register(new Emitter()); public readonly onDprChange = this._onDprChange.event; @@ -27,6 +27,8 @@ export class CoreBrowserService extends Disposable implements ICoreBrowserServic ) { super(); + this._screenDprMonitor = this._register(new ScreenDprMonitor(this._window)); + // Monitor device pixel ratio this._register(this.onWindowChange(w => this._screenDprMonitor.setWindow(w))); this._register(EventUtils.forward(this._screenDprMonitor.onDprChange, this._onDprChange));