Extension host OOM crash: glob.ts compiles an arbitrarily long watcher pattern into a pathological regex (regExp.test blows the V8 heap)
@dmitrivMS is already working on this.
Since Jun 16, 2026.
Assessment
This issue has not been assessed yet.
Description
Does this issue occur when all extensions are disabled?: Yes
- VS Code Version: VS Code 1.124.2 (commit 6928394f91b684055b873eecb8bc281365131f1c)
- OS Version: macOS 26.5.1 (arm64)
Note: local username scrubbed to userx in all captured strings.
Does this issue occur when all extensions are disabled?: No (end-to-end), but the crash is reproducible WITH extensions disabled
The end-to-end crash is triggered by a language extension (gopls / vscode-go) supplying a bad watch pattern, so disabling all extensions removes the trigger. However, the defect itself is in VS Code core (vs/base/common/glob.ts) and is reproducible with no extensions at all by feeding the attached pattern directly to the glob API (see Steps to Reproduce) — glob.parse(pattern) + a single match(path) OOMs the host. So this is not an "extension bug" to forward to a publisher: the core defect is that glob.ts compiles an arbitrary, untrusted, multi-kilobyte string into a regex and runs it on every file event with no length or complexity guard, so a single malformed pattern from any extension can OOM-kill the entire extension host.
- VS Code Version: 1.124.2 (6928394f91b684055b873eecb8bc281365131f1c)
- OS Version: macOS 26.5.1, arm64
- Insiders: the faulting code path (
glob.tsparseRegExp/regExp.test) is unchanged onmain, so this is expected to reproduce on the latest Insiders as well.
Summary
A file-watcher glob pattern that is not a real glob — in my case the multi-line error output of a failed go list (~6.5 KB, dozens of missing go.sum entry ... lines) — gets compiled by glob.ts into an 8,691-character regex containing 459 [/\\] path-separator character classes. On the very next file-system event, extHostFileSystemEventService.$onFileEvent runs regExp.test(path) against that regex, which exhibits catastrophic backtracking / unbounded memory growth and OOM-crashes the extension host.
Because this happens inside the extension host, it silently kills any in-flight extension work. In my case it repeatedly cancelled in-flight GitHub Copilot Chat requests (they surfaced as "Canceled"), which is how I found it — but the editor-level defect is independent of Copilot.
The root problem is defense-in-depth: glob.ts trusts the pattern string completely. A malformed pattern should fail safe (be rejected / produce a non-matching matcher), never OOM the host.
Steps to Reproduce
I have preserved the exact captured pattern and compiled regExp as a minimal repro. The shortest faithful reproduction:
import { parse } from 'vs/base/common/glob';
// `pattern` = the ~6.5 KB non-glob string captured from the watcher
// (the literal multi-line output of a failed `go list`, full of
// "missing go.sum entry for module ... to add: go get ..." lines)
const pattern = /* contents of the attached `pattern` file */;
const match = parse(pattern); // compiles to an ~8.6 KB regex
match('/users/userx/go/src/app/some/package/file.go');
// → catastrophic backtracking → V8 heap OOM
How it arises organically (real-world trigger):
- Open a Go workspace where
go list ./...fails (e.g. missinggo.sumentries for an imported module). - gopls / vscode-go surfaces that failure string and it ends up registered as a file-watch glob pattern (a 6.5 KB multi-line string — clearly not a glob).
glob.tscompiles it into the pathological regex above.- Save any
.gofile →$onFileEvent→regExp.test(path)→ extension host OOM.
Smoking gun (extension-host debugger)
Running Developer: Show Running Extensions with a profile attached and reproducing the crash, the debugger paused with the banner "PAUSED BEFORE OUT OF MEMORY EXCEPTION". Faulting frame and call stack (top-down):
<anonymous> glob.ts ← regExp.test(path) → OOM
n glob.ts
<anonymous> extHostFileSystemEventService.ts
E._deliver / _deliverQueue / fire event.ts
Dw.$onFileEvent extHostFileSystemEventService.ts ← a file-system event
i._doInvokeHandler / _invokeHandler / _receiveRequest / _receiveOneMessage rpcProtocol.ts
At the breakpoint:
path= the.gofile being saved (a path under my workspace)regExp= an 8,691-character regexpattern= the 6,562-character source string it was compiled from- the regex contains 459
[/\]separator classes
(The attached sanitized repro reproduces the same shape at 6,512 / 8,628 bytes and 495 separator classes.)
The pattern begins (sanitized — real package names replaced):
'/users/userx/go/src/app/go list failed to return compiledgofiles for "main".build constraints exclude all go files in /users/userx/go/pkg/mod/example.test/x/sys@v0.0.0/windowsmissing go.sum entry for module providing package example.test/module/group/area/section/pkg00 (imported by app/src/component/area/section/pkg00); to add:go get app/src/component/area/section/pkg00 ... (32 such "missing go.sum entry" entries) ...
The compiled regExp begins (sanitized):
/^'[/\]users[/\]userx[/\]go[/\]src[/\]app[/\]go list failed to return compiledgofiles for "main"\.build constraints exclude all go files in [/\]users[/\]userx[/\]go[/\]pkg[/\]mod[/\]example\.test[/\]x[/\]sys@v0\.0\.0[/\]windowsmissing go\.sum entry for module providing package exa ...
Expected behavior
glob.ts should fail safe against pathological / non-glob patterns and never be able to OOM-crash the extension host:
- Reject or truncate patterns above a sane length (a 6.5 KB watch glob is never legitimate).
- Cap regex complexity (e.g. number of separator classes / alternations) and fall back to a literal/non-matching matcher when exceeded.
- Optionally guard
regExp.testwith a complexity or step budget.
A malformed watch pattern from an extension should at worst log a warning and not match — it must not be able to take down the host.
Actual behavior
glob.ts compiles the 6.5 KB string into an 8,691-char regex; the first regExp.test(path) on a file event causes catastrophic backtracking and OOMs the extension host, silently killing all in-flight extension work.
Attachments
Two files reproduce it deterministically (paths sanitized; structure/size preserved):
pattern.txt— the ~6.5 KB non-glob source string (failedgo listoutput)regExp.txt— the ~8.6 KB compiled pathological regex
(Drag these two files into the GitHub issue before submitting. They are sanitized: the local username is userx and all internal package paths are generic placeholders — only the failed-go list structure remains.)
Notes on the upstream trigger (separate issue, FYI only)
The source of the bad pattern is gopls / vscode-go registering a failed go list error string as a watch glob. That is a second, separate bug I may file against golang/vscode-go. This issue is specifically about VS Code core (glob.ts) not being robust against such a pattern — that hardening protects against any extension (Go, .NET, or otherwise) leaking an oversized string into a watch pattern.
- Dominant language
- TypeScript
- Stars
- 193k
- Forks
- 42.9k
- PR merge metrics
- PR metrics pending
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from microsoft/vscode
-
testplan-item
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
-
new release
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
-
testplan-item
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
-
Difficulty 2/5 1-3 hours Newbie friendliness 84/100
-
testplan-item
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
All issues in microsoft/vscode
Similar issues
-
clawsweeper:fix-shape-clear clawsweeper:queueable-fix clawsweeper:source-repro impact:ux-friction issue-rating: 🦞 diamond lobster no-stale P3
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
-
community first-timers-only good first issue hacktoberfest help wanted low hanging fruit up-for-grabs
Difficulty 1/5 Under an hour Newbie friendliness 76/100
-
code-quality refactoring
Difficulty 2/5 1-3 hours Newbie friendliness 84/100
github/gh-aw-firewall#8816 ·
-
integration:quickjs org:external priority:backlog topic:code-interpreter topic:middleware type:feature
Difficulty 2/5 1-3 hours Newbie friendliness 74/100
langchain-ai/deepagents#6450 ·
-
Difficulty 1/5 Under an hour Newbie friendliness 88/100
vercel/react-tweet#225 ·