// guides

VS Code Extension Security: How to Vet and Allow-List Extensions

VS Code extension security concept: unsandboxed extension host reaching a developer's keys, tokens and terminal

VS Code extensions are not sandboxed: they run as you, with full access to your files, network, processes and secrets, and the marketplaces that ship them scan for malware but do not audit every version's code. That turns every extension install and every auto-update into a supply-chain decision your organization has to make on purpose.

The short answer

  • VS Code, Cursor and Windsurf run extensions in an unsandboxed Node.js extension host with the developer's full OS privileges. There is no permission manifest and no install-time capability prompt.
  • The VS Code Marketplace and Open VSX offer automated scanning and publisher identity checks, not a code audit, and updates generally reach clients without a human re-review.
  • Allow-list by extension ID, pin versions, review the VSIX artifact rather than the GitHub repo, disable auto-update for unreviewed versions, and watch extension-host egress.
  • Your policy must cover every fork and registry, remote hosts under ~/.vscode-server, and AI agents that can run code –install-extension on their own.

Key takeaways

  • VS Code-family extensions run unsandboxed in a Node.js extension host with the developer's full OS privileges and no permission manifest.
  • Marketplace scanning and the verified-publisher badge are identity and known-malware checks, not code audits, and updates generally ship without a human re-review.
  • Publisher takeover and ownership transfer turn one bad version into a fleet-wide compromise through auto-update.
  • Workspace Trust gates untrusted folders; it does not constrain an installed extension.
  • Cursor, Windsurf, VSCodium and Codespaces use different registries and settings, so one allowlist rarely covers the whole org, and agents with auto-run are a separate install path.

Are VS Code extensions sandboxed, or do they run with your privileges?

No. VS Code and its forks, including Cursor, Windsurf and VSCodium, run extensions in the extension host: a separate Node.js process that executes as the logged-in OS user. The split keeps a crashing extension from taking down the editor UI. It was built for stability and was never designed as a security boundary.

Inside that process an activated extension has the full Node.js runtime: fs, net, child_process and process.env. It can read and write any file your user can, spawn shells, open sockets and enumerate machine identifiers. The extension API has no capability manifest, so nobody ever sees a prompt like “this extension wants to read your home directory.”

Platform Execution model Declared permissions Install-time warning
VS Code, Cursor, Windsurf, VSCodium Node.js extension host as the OS user None None
Chrome (Manifest V3) Browser extension sandbox Yes, in manifest Yes
JetBrains IDEs Plugins inside the IDE’s JVM No fine-grained scopes No, but marketplace approval step

Read the first row as a rule: installing a VS Code-family extension is the same trust decision as running an unsigned program from its publisher.

Activation events decide when that code runs. "*", onStartupFinished, onLanguage:* and workspaceContains: give an extension near-permanent execution. Malicious samples pair broad activation with delayed, timer-driven network calls, so nothing looks odd at startup.

Workspace Trust does not change this

Workspace Trust, added in VS Code 1.57 in mid-2021, opens untrusted folders in Restricted Mode and blocks automatic tasks, debug configurations and some extension features. It protects you from a hostile repository’s config files. It does nothing to an extension that is already installed and activated.

The flag that decides whether an extension runs in Restricted Mode, capabilities.untrustedWorkspaces in package.json, is declared by the author and not verified by the marketplace. Keep security.workspace.trust.enabled on, but file it under repository hygiene, not extension control.

Does the VS Code Marketplace actually review extensions before publishing?

Partly. Microsoft’s marketplace runs automated malware scanning, adds some manual review, and offers a verified-publisher badge that proves control of a domain or GitHub organization. Microsoft’s terms put responsibility for extension behavior on the publisher. The blue checkmark tells you who published the code, not what the code does.

Open VSX, run by the Eclipse Foundation, is the default registry for VSCodium and Eclipse Theia. Its moderation team is small relative to its volume. Treat it as a separate trust boundary in procurement, not as a mirror of Microsoft’s gallery.

Forks widen the problem. Cursor has historically pulled from Open VSX and now fronts its own registry; Windsurf has its own distribution. The same extension ID can resolve to different code in different registries, and a VS Code allowlist does not govern Cursor users. Check what each editor in your fleet points at today.

The bigger gap is updates. Publishers push new versions and clients pull them automatically, generally without a human re-review on either gallery. Your install-time vetting covered one version, and the client will silently replace it.

Install counts do not close the gap. They are cumulative, easy to inflate and survive ownership transfers. A typosquat also borrows credibility from the name it imitates.

How do trusted extensions turn malicious?

Malicious extensions arrive through six paths. Only the first is a publisher you have never heard of; the other five are ways code you already trust turns hostile.

  • Typosquatting and impersonation. Lookalike names and icons. A 2023 proof of concept that copied the popular Darcula theme picked up installs from developers inside real companies.
  • Publisher account takeover. One stolen token, one malicious version, every installation updated. This is the highest-impact path (MITRE ATT&CK T1195.002).
  • Ownership transfer. A maintainer sells or hands off a popular extension. The install base and reputation move with it; the new owner’s intent does not show up in metadata.
  • Bundled npm dependencies. A clean author can ship a compromised transitive package. event-stream (2018), ua-parser-js (2021) and the Shai-Hulud npm worm (September 2025, with a second wave in late November) show how this lands.
  • Extension packs. extensionPack and extensionDependencies pull in code you never evaluated individually.
  • Self-propagation. Koi Security’s GlassWorm campaign (October 2025, second wave in November) hid payloads in invisible Unicode characters, used a Solana-based command-and-control channel, hit both Microsoft’s gallery and Open VSX, and spread through stolen developer credentials.

GlassWorm is the case to brief leadership on. It shows the editor is not an isolated endpoint: a compromised IDE becomes a launch point into other extensions, other repositories and other developers. For an AI-tooling example, our write-up on the Cursor marketplace SSH trust failure covers a build impersonating a well-known AI coding extension that left an SSH backdoor.

Malicious VS Code extension spreading through an update channel, illustrating extension supply chain compromise
One bad version from a trusted publisher reaches every installation.

Can a malicious VS Code extension read SSH keys, cloud credentials and tokens?

Yes, with nothing more than standard Node.js file reads. ~/.ssh, ~/.aws/credentials, ~/.npmrc, ~/.gitconfig, ~/.kube/config and browser profile directories are readable by your user, so they are readable by the extension host.

Three less obvious channels matter more in practice:

  • OAuth through the editor. The vscode.authentication API lets an extension request GitHub or Microsoft tokens. The user sees a consent dialog, the scope can be as broad as repo, and the token goes straight to extension code.
  • Terminal output. Shell integration lets an extension observe what aws, gh, kubectl or psql print, and workbench.action.terminal.sendSequence lets it type commands into your shell.
  • Webviews. With enableScripts and no CSP, an extension can render a sign-in page that looks exactly like VS Code’s own UI.

Exfiltration rarely looks exotic. HTTPS to a legitimate SaaS API blends into normal developer traffic, which is why most EDR deployments do not flag it. The realistic blast radius is source code, cloud and registry credentials, signing keys, and from there, CI pipelines and production.

How do you audit a VSIX before you install it?

Review the artifact that ships, not the GitHub repository. The repository field in package.json is self-declared, and the published bundle is usually minified and may not match the source. A VSIX is a ZIP you can inspect without executing.

  1. Confirm the exact ID. publisher.name, character for character. Check publisher age, other extensions, and whether ownership changed recently.
  2. Unpack in an empty directory. mkdir /tmp/vsix-review && unzip -q ext.vsix -d /tmp/vsix-review. Do not open the folder in your editor.
  3. Read the manifest. In extension/package.json, compare activationEvents, extensionDependencies, extensionPack, authentication providers and untrusted-workspace claims against what the extension says it does.
  4. Grep the bundle for capability. grep -rnE 'child_process|process\.env|\.ssh|credentials|eval\(|new Function|sendSequence' /tmp/vsix-review/extension. A color theme needs none of these.
  5. Hunt hidden payloads. grep -rlP '[\x{200B}-\x{200D}\x{FE00}-\x{FE0F}]' /tmp/vsix-review catches the zero-width and variation-selector tricks GlassWorm used. Add TruffleHog for embedded secrets and Semgrep or YARA rules for network and obfuscation patterns.
  6. Inventory bundled dependencies. Run bundled node_modules through Socket.dev or your SCA tool and generate a CycloneDX or SPDX SBOM, because the VSIX will not come with one.

For extensions with real privilege (Git, cloud, database, AI assistants), a bundle diff on every version bump is cheaper than an incident, and it fits manual secure code review.

Signals that block an install outright

  • An ID one character away from a popular extension, or a publisher created in the last few weeks.
  • "*" or onStartupFinished activation on a cosmetic or language-specific extension.
  • child_process, credential-path reads or sendSequence in a theme, icon pack or snippet extension.
  • Invisible Unicode, large base64 or hex blobs, or eval over decoded strings.
  • Calls to blockchain RPC endpoints, paste sites or hardcoded IPs.
  • A recent ownership transfer followed by a version that adds network or process capability.
  • OAuth requests broader than the feature needs.
  • Sideloaded .vsix files sent over chat or email. Manual install skips even the gallery’s scanning.
VSIX security audit concept: unpacked extension archive inspected for hidden payloads and bundled dependencies
Review the artifact that ships, not the repository it claims to come from.

How do you enforce an extension allowlist across editors and agents?

Run deny-by-default by extension ID, with a fast intake path so developers request extensions instead of routing around you. Current VS Code releases support an extensions.allowed policy setting that accepts extension IDs, publisher-level entries and version constraints. Forks may not honor it, so test the policy in each editor build you deploy.

{
 "extensions.allowed": {
 "ms-python.python": true,
 "esbenp.prettier-vscode": ["11.0.0"],
 "*": false
 },
 "extensions.autoUpdate": false,
 "security.workspace.trust.enabled": true
}

Push it through Intune, MDM or managed settings, and back it with WDAC or AppLocker where you need to stop unmanaged editor binaries.

Approach Stops Misses Operational cost
Allowlist Typosquats, unknown publishers Bad updates to allowed IDs unless pinned Medium: needs intake SLA
Blocklist Known-bad IDs Everything new Low, and low value
Private gallery mirror Unreviewed versions, sideloads Bad code you approved High: hosting and re-review
Extension-host egress filtering Exfiltration to unknown hosts Exfil through allowed SaaS APIs Medium to high

For most teams the workable setup is an allowlist, version pinning for privileged extensions, a 48-hour intake SLA, and a quarterly review that removes anything unused.

Inventory per editor directory: ~/.vscode/extensions, ~/.cursor/extensions, ~/.windsurf/extensions, and ~/.vscode-server/extensions on bastions, build boxes and WSL, which tend to carry looser sets. Include devcontainer.json, whose customizations.vscode.extensions block lets a cloned repository decide what installs in Dev Containers and GitHub Codespaces.

Agents and MCP servers are an install path too

An agent with terminal auto-run can execute code --install-extension as easily as npm test. Prompt injection in a dependency README, an issue or a fetched web page can become an extension install with no human click. Deny --install-extension to agents and require allow-listed commands for agent terminal execution.

MCP servers configured in the IDE run with the user’s privileges, usually hold API keys, and come from package registries with even less review than extensions. Put them in the same inventory. MCP server and tool-chain security testing checks whether those controls hold when the agent is the one being manipulated.

What do you do when an installed extension goes bad?

Catch it at the update, because the dangerous event is the unattended auto-update. Diff the fleet’s code --list-extensions --show-versions output daily against the approved list, and alert on any new version of a privileged extension that has not been through review.

On the endpoint, have EDR attribute network and process activity to the extension host, which appears as a Node or Electron helper child of the editor. Child shells, reads of credential paths, and connections to blockchain RPC or paste hosts are the high-signal events.

When an extension is confirmed bad, uninstalling it is step six, not step one:

  1. Isolate affected machines and snapshot the extension directory for forensics.
  2. Revoke and rotate every reachable secret: SSH keys, cloud keys, npm and PyPI tokens, GitHub OAuth grants, kube configs.
  3. Check for persistence outside the editor: shell profiles, scheduled tasks, launch agents, other extensions modified on disk.
  4. Review recent commits and pushes from affected users for injected code.
  5. Block the ID and version fleet-wide.
  6. Remove the extension and rebuild from a clean baseline.

The minimum standard for your SDLC

Seven rules cover most of the risk and fit on one page:

  • Deny by default; allow by exact extension ID per editor and registry.
  • Pin versions for extensions with process, network, credential or OAuth capability.
  • Review the VSIX artifact on intake and on every version bump of a pinned extension.
  • Block .vsix sideloading and third-party galleries outside the approved list.
  • Inventory local, remote-server, container and Codespaces extensions on a schedule.
  • Put MCP servers and agent auto-run under the same allowlist.
  • Map the control to SSDF (NIST SP 800-218) and your SOC 2, ISO 27001, NIS2 or Cyber Resilience Act evidence, so it survives audits and budget cycles.
VS Code extension security diagram concept: extension host reaching files, keys and network with full user privileges
The extension host is a stability boundary, not a security one.

FAQ

Are VS Code extensions sandboxed?

No. VS Code, Cursor and Windsurf run extensions in an extension-host Node.js process as the logged-in user, with filesystem, network, process and environment access. There is no permission manifest, no install-time capability prompt, and Workspace Trust does not sandbox an activated extension.

Does the verified publisher checkmark mean an extension is safe?

No. It means the publisher proved control of a domain or GitHub organization. It says nothing about what the code does or what the next version will do.

Can a VS Code extension steal my AWS keys or GitHub token?

Yes. Any activated extension can read ~/.aws/credentials and ~/.ssh, request GitHub OAuth tokens through the editor's authentication API, and capture secrets printed in the integrated terminal.

What is the difference between the VS Code Marketplace and Open VSX?

The VS Code Marketplace is Microsoft's gallery for VS Code. Open VSX is the Eclipse Foundation's open registry, used by VSCodium, Eclipse Theia and historically Cursor. They have separate moderation and the same extension ID can map to different code, so treat them as separate trust boundaries.

Should we block .vsix sideloading?

Yes, outside a controlled intake process. A manually installed VSIX bypasses even the gallery's automated scanning, and VSIX files passed around over chat or email are a common delivery route for impersonation.

If you want an outside team to inventory your editors, review high-privilege extensions and test whether your allowlist survives an agent with a shell, our AI supply chain security audit covers extensions, MCP servers and plugins in one pass.



// get started

Work with AgentOffense

Tell us about your target and goals. We’ll reply with scope and a fixed-price quote — usually within one business day.

./request_engagement