Security: Skip config resolution in untrusted workspaces#3972
Merged
Conversation
Prettier's resolveConfigFile/resolveConfig can require()/import() JavaScript config files (.prettierrc.js, prettier.config.js, etc.), allowing arbitrary code execution even when workspace trust restricted module resolution to the bundled Prettier. Add a workspace.isTrusted guard in resolveConfig() to skip config resolution entirely in untrusted workspaces, returning null (Prettier defaults). Reported by Hector Ruiz Ruiz. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
Pull request overview
This PR hardens the Prettier VS Code extension against workspace trust bypasses by preventing Prettier config resolution from running in untrusted workspaces (avoiding execution of JavaScript-based config files during resolveConfig).
Changes:
- Add an early
workspace.isTrustedguard inModuleResolverNode.resolveConfig()to skip config resolution and fall back to defaults. - Introduce a new log message constant explaining config resolution is skipped in untrusted workspaces.
- Document the security fix in
CHANGELOG.md.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| src/message.ts | Adds a new message constant for logging when config resolution is skipped in untrusted workspaces. |
| src/ModuleResolverNode.ts | Skips Prettier config resolution entirely when workspace.isTrusted is false to prevent JS config execution. |
| CHANGELOG.md | Adds an Unreleased entry describing the security fix and its impact. |
When requireConfig is true and the workspace is untrusted, return "disabled" instead of null so formatting is correctly skipped rather than proceeding with VS Code defaults. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
.prettierrc.js,prettier.config.js,.prettierrc.cjs) in untrusted workspaces, bypassing workspace trust protectionsworkspace.isTrustedguard at the top ofresolveConfig()inModuleResolverNode.tsthat returnsnull(use Prettier defaults) when the workspace is untrustedformat()→getResolvedConfig()→resolveConfig()) and the plugin discovery path (getSelectors()→resolveConfig())Security Details
When a workspace is untrusted,
getPrettierInstance()correctly forces the bundled Prettier. However,resolveConfig()still called Prettier'sresolveConfigFile()/resolveConfig(), which internallyrequire()/import()JavaScript config files — allowing arbitrary code execution in the extension host with the user's privileges.Reported by Hector Ruiz Ruiz (discovered 10/12/2025).
Test plan
npm run compilesucceedsnpm testpasses with no regressions.prettierrc.cjscontaining a side-effect (e.g.,require('fs').writeFileSync('/tmp/test-vuln', 'executed')), open it as untrusted, format a file, confirm the side-effect does NOT occur🤖 Generated with Claude Code