How to Audit Your VS Code Extensions for Security
The GitHub breach happened through a VS Code extension. Here's how to check what you have installed and reduce your exposure in 10 minutes.
On this page
In May 2026, a compromised version of the Nx Console VS Code extension (nrwl.angular-console) was live on the official marketplace for 18 minutes. One GitHub employee installed it during that window. The result: 3,800 internal repositories exfiltrated, plus tokens for GitHub, npm, AWS, and cloud credential stores collected silently before the malicious version was pulled.
Eighteen minutes was enough because VS Code extensions run with zero sandboxing. They share the same Node.js process, the same file system access, and the same network privileges as VS Code itself. When a trusted extension pushes a malicious update, every machine that auto-updates becomes an open door.
If you use VS Code, this matters to you. Not because you are a target today, but because the same trust model you rely on every day was the attack surface. This guide walks through exactly what to do right now: audit what you have installed, reduce your exposure, harden VS Code's own settings, and build a recurring habit that takes ten minutes per quarter.
Why Extensions Are More Dangerous Than They Look
VS Code extensions are not sandboxed. When you install one, it runs with the same permissions as VS Code itself. Unlike browser extensions, which operate in a restricted environment with explicit permission prompts, a VS Code extension gets blanket access the moment you click "Install".
- It can read every file in your open workspace, including
.env.local,.ssh/config, and any credential file. - It can access environment variables set in your shell session, including cloud provider tokens and API keys.
- It can spawn child processes and make outbound network requests, silently, with no user notification.
- It can register activation events that trigger on file open, language detection, or workspace load, running code before you interact with it.
- A verified publisher badge proves domain ownership, not that every update pushed under that account is safe.
The Nx Console breach was not an anomaly. In 2025, researchers at Aqua Security published a study showing that typosquatted VS Code extensions could harvest credentials within seconds of installation. They created proof-of-concept extensions mimicking popular tools and collected data from thousands of developers who installed them by accident. The marketplace's verification system caught none of these before publication.
How a Malicious Extension Actually Works
Understanding the attack mechanics helps you recognize suspicious behavior. A compromised extension typically does three things in the first seconds after activation.
- 1
Harvest credentials from the file system
The extension scans predictable paths for credential files. On macOS and Linux, these include
~/.ssh/,~/.aws/credentials,~/.npmrc, and any.envfiles in open workspaces. On Windows, the equivalent paths under%USERPROFILE%are targeted.typescript — What credential harvesting looks like in extension code// Simplified example of what a malicious extension activation might do import * as fs from "fs"; import * as os from "os"; import * as https from "https"; const targets = [ `${os.homedir()}/.ssh/id_rsa`, `${os.homedir()}/.aws/credentials`, `${os.homedir()}/.npmrc`, ]; for (const file of targets) { if (fs.existsSync(file)) { const content = fs.readFileSync(file, "utf-8"); // Exfiltrate via HTTPS POST to attacker-controlled server exfiltrate(content); } } - 2
Read environment variables from the running process
Every environment variable in your shell session is available to extensions via
process.env. If you exportGITHUB_TOKEN,AWS_SECRET_ACCESS_KEY, orDATABASE_URLin your.zshrcor.bashrc, every installed extension can read those values.typescript// All of these are trivially accessible to any extension const githubToken = process.env.GITHUB_TOKEN; const awsKey = process.env.AWS_SECRET_ACCESS_KEY; const dbUrl = process.env.DATABASE_URL; - 3
Exfiltrate data over the network
Extensions can make outbound HTTPS requests with no user notification. The data leaves your machine in a standard web request that most firewalls and proxy tools will not flag. Some sophisticated attacks encode the stolen data as DNS queries or embed it in seemingly innocent telemetry payloads, making detection even harder.
The 10-Minute Audit
Start by seeing what you have installed:
code --list-extensionsCount the output. If you have more than 20, you almost certainly have some you no longer use: extensions installed once for a specific project, forgotten tutorial plugins, outdated tools. Unused extensions are pure attack surface with zero upside.
For a more detailed view, pipe the list into a format that shows version numbers. This helps you cross-reference against known-compromised versions if an incident is announced:
code --list-extensions --show-versionsFor every extension you actively use, work through this checklist:
- Verified publisher badge: blue checkmark next to publisher name. Means domain ownership verified + 6 months good standing. Missing badge = extra scrutiny.
- Last update date: extension not updated in 1+ year is unlikely to receive security patches. Evaluate whether you still need it.
- GitHub repository: click through from the marketplace page. Check: are issues being responded to? Is the last commit recent? Does it look maintained?
- No GitHub link: closed-source with no public repository is a black box. Consider alternatives with public, auditable code.
- Permission scope: check if the extension registers broad activation events like
*(activates on everything) instead of specific language or file triggers. - Download count trend: a sudden spike in downloads from a previously low-traffic extension can indicate typosquatting promotion.
- Uninstall unused extensions: if you haven't used it since your last audit, remove it.
How to Inspect an Extension Before Installing
Every VS Code extension is a .vsix file, which is just a ZIP archive containing JavaScript and a manifest. You can inspect what an extension actually does before trusting it with your file system.
# Find your installed extensions directory
# macOS/Linux:
ls ~/.vscode/extensions/
# Inspect a specific extension's package.json for activation events
cat ~/.vscode/extensions/publisher.extension-name-1.0.0/package.json | grep -A 10 "activationEvents"
# Check what permissions/capabilities it declares
cat ~/.vscode/extensions/publisher.extension-name-1.0.0/package.json | grep -A 5 "contributes"The activationEvents field in package.json tells you when the extension's code runs. An extension with "activationEvents": ["*"] activates on every VS Code startup, regardless of what you are working on. Extensions that activate on specific languages (like "onLanguage:python") are more narrowly scoped and present less risk.
For a deeper inspection, look at the extension's compiled JavaScript in the out/ or dist/ directory. Search for suspicious patterns like outbound HTTP requests to unknown domains, file system reads targeting credential paths, or calls to child_process.exec.
# Look for outbound network calls
grep -r "https://" ~/.vscode/extensions/publisher.extension-name-1.0.0/dist/ | grep -v "node_modules"
# Look for file system access to sensitive paths
grep -rE "(.ssh|.aws|.npmrc|.env)" ~/.vscode/extensions/publisher.extension-name-1.0.0/dist/
# Look for child process spawning
grep -r "child_process" ~/.vscode/extensions/publisher.extension-name-1.0.0/dist/Reducing Your Attack Surface
You cannot disable auto-updates entirely without stopping security patches. But you can limit what extensions can reach and how many of them are active at any given time.
- Enable extensions per-workspace. If an extension is only needed for one project, enable it only for that workspace. It will not run in other projects and cannot touch those credentials.
- Use a separate VS Code profile for sensitive work. Profiles let you maintain different extension sets: a general dev profile and a locked-down profile for anything involving production secrets or client code.
- Keep <code>.env</code> files out of VS Code workspaces where possible. When you open a folder, every extension can see all files in it. Use a secrets manager or set variables in your deployment dashboard instead of local files.
- Disable extensions you use infrequently. Instead of uninstalling, you can disable an extension globally and re-enable it per-workspace when needed. This keeps it available without giving it permanent access.
VS Code Settings You Should Change Today
Beyond managing extensions, VS Code itself has settings that affect your security posture. These changes take under five minutes and apply globally.
| Setting | Recommended Value | Why It Matters |
|---|---|---|
| <code>extensions.autoUpdate</code> | <code>onlyEnabledExtensions</code> | Only auto-updates extensions you have explicitly enabled, not disabled ones sitting idle. |
| <code>security.workspace.trust.enabled</code> | <code>true</code> | Prompts you before trusting new workspaces. Extensions with restricted mode support will run with limited capabilities in untrusted workspaces. |
| <code>security.workspace.trust.untrustedFiles</code> | <code>prompt</code> | Asks before opening files from untrusted sources, preventing automatic extension activation on malicious files. |
| <code>terminal.integrated.env.linux</code> (or <code>.osx</code>) | Remove sensitive variables | Prevents VS Code's integrated terminal from inheriting secrets you set in your shell profile. |
| <code>telemetry.telemetryLevel</code> | <code>off</code> or <code>crash</code> | Reduces the data VS Code itself sends. Extensions have their own telemetry, which this does not control. |
{
"extensions.autoUpdate": "onlyEnabledExtensions",
"security.workspace.trust.enabled": true,
"security.workspace.trust.untrustedFiles": "prompt",
"telemetry.telemetryLevel": "off"
}If You Are Affected: Response Playbook
If you had Nx Console (nrwl.angular-console) installed between 12:30 and 12:50 UTC on May 18, 2026, treat your credentials as compromised. The same logic applies to any extension you are not certain about. Do not wait to be certain: rotating takes two minutes, breach recovery takes weeks.
- 1
Rotate tokens immediately
In priority order:
- GitHub personal access tokens: Settings > Developer settings > Personal access tokens > delete and recreate
- npm publish tokens: npmjs.com > Access Tokens > generate new token
- AWS access keys: IAM > Users > Security credentials > deactivate old key, create new key
- Any other cloud provider tokens the machine had access to (GCP service account keys, Azure SPN secrets, DigitalOcean API tokens)
bash# Verify your current GitHub token is valid (run after rotating) gh auth status # Check for any unauthorized SSH keys added to your GitHub account gh ssh-key list # List active GitHub personal access tokens gh auth token - 2
Check your security logs
Review your GitHub security log for unexpected actions in the 48 hours after the suspicious install. Attackers often create new tokens or OAuth apps immediately after gaining access, so look for authorization events you do not recognize.
- GitHub: Settings > Security log: look for unexpected OAuth authorizations, repository clones, or token creation
- npm: check your publish history and authorized packages for unexpected publishes
- AWS: CloudTrail > Event history: filter by your IAM user for the relevant time window
- Check
~/.bash_historyor~/.zsh_historyfor commands you did not run, which could indicate process spawning by a malicious extension
- 3
Revoke and regenerate remaining credentials
- Any API keys used by services running on your machine (PostHog, Stripe, Twilio, etc.)
- If you use a password manager integration in VS Code (1Password, Bitwarden), rotate the access token for that integration
- Database credentials if your machine had a local
.env.localwith production values - Docker Hub tokens if you push images from your local machine
- Any SSH keys stored in
~/.ssh/, especially if they grant access to production servers
The Quarterly Audit Habit
This is not a one-time fix. New extensions get compromised. Maintainers abandon projects. Publishers sell their accounts. Set a recurring calendar reminder for every three months and run through this checklist.
- Run
code --list-extensionsand remove anything unused since the last audit - Check that actively-used extensions still have a verified publisher badge and recent commits
- Review which extensions are enabled globally versus workspace-only
- Confirm critical credentials (GitHub, npm, AWS) have been rotated within the last 90 days
- Search security advisories for any extensions on your list that had recent incidents
- Verify your VS Code Workspace Trust settings are still enabled
If your team uses a shared VS Code extensions recommendation file (.vscode/extensions.json), audit that file as part of your quarterly review. A compromised recommendation means every new team member installs the malicious extension on day one.
{
"recommendations": [
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode",
"bradlc.vscode-tailwindcss"
],
"unwantedRecommendations": [
"known-compromised.extension-id"
]
}Extension Security for Teams
Individual audits matter, but teams multiply the risk surface. If ten developers each install different extensions with no oversight, the team's collective exposure is the union of all their extension lists. A few simple policies reduce this significantly.
- Maintain an approved extensions list. Keep a curated
.vscode/extensions.jsonin your repository with only vetted extensions. Review additions through pull requests. - Use VS Code profiles for onboarding. New team members import the team profile, which includes only approved extensions and security-hardened settings.
- Document your extension policy. A one-page doc covering which extensions are approved, how to request new ones, and what to do if an extension is flagged in a security advisory.
- Run periodic extension audits across the team. Have each developer export their extension list quarterly and compare against the approved list.
Frequently Asked Questions
How do I know if I was affected by the May 2026 Nx Console breach?
If you had nrwl.angular-console (also listed as "Nx Console" in the marketplace) installed and VS Code's auto-update ran between 12:30 and 12:50 UTC on May 18, 2026, treat all credentials on that machine as compromised.
- Rotate immediately: GitHub tokens, npm tokens, AWS access keys, in that order
- Check your GitHub security log for unexpected actions in the 48 hours after the install
- Check npm for unexpected publishes, AWS CloudTrail for unexpected API calls
- Review your SSH keys and remove any you do not recognize
Are VS Code extensions sandboxed at all?
No. Extensions run in a Node.js process with full access to your file system, environment variables, and network. There is no permission model, no capability restrictions, and no runtime isolation between extensions. This is by design (many legitimate extensions need deep system access), but it makes every extension a potential security surface.
VS Code does support Workspace Trust, which restricts some extension capabilities in untrusted workspaces. However, this only applies if both the extension author opts in to restricted mode and you have Workspace Trust enabled. Most extensions do not implement restricted mode.
Does a verified publisher badge mean an extension is safe?
It means the publisher verified domain ownership and maintained good standing for at least six months. It does not mean every update they push is safe. The Nx Console breach (nrwl.angular-console) happened through a verified publisher whose account token was stolen. A badge reduces risk, it does not eliminate it.
Think of the verified badge as similar to an HTTPS certificate: it confirms identity, not intent. A compromised account with a verified badge is more dangerous than an unverified one because users trust it more.
Can I disable VS Code extension auto-updates?
Yes. Go to Settings, search Extensions: Auto Update, and set it to false or onlyEnabledExtensions. The trade-off with fully disabling: you also stop receiving legitimate security patches automatically.
A more practical approach is to set auto-update to onlyEnabledExtensions (updates only extensions you have explicitly enabled), combine it with per-workspace extension enablement, and review the VS Code release notes periodically for any reported extension security issues.
Are open-source extensions safer than closed-source ones?
| Open-source | Closed-source | |
|---|---|---|
| Code visibility | Full: audit before installing | None: black box |
| Malicious commit detection | Community catches it faster | Relies on Microsoft review only |
| Trust basis | Code + publisher reputation | Publisher reputation only |
| Supply chain risk | Depends on maintainer security | Depends on publisher security |
Open-source is better, but not foolproof. The published .vsix on the marketplace may not match the source code in the repository. Some sophisticated attacks modify only the published artifact while keeping the GitHub repository clean. When choosing between two extensions with similar functionality, prefer the one with a public, actively-maintained repository and a build pipeline you can verify.
What is extension typosquatting and how do I avoid it?
Typosquatting is when an attacker publishes an extension with a name very similar to a popular one, hoping developers will install it by mistake. For example, pretier-vscode instead of prettier-vscode, or python-extension instead of ms-python.python.
To avoid typosquatting: always install extensions by searching for the exact publisher ID (like esbenp.prettier-vscode), not just the display name. Verify the publisher is who you expect before clicking install. If a team member recommends an extension, share the full marketplace URL rather than just the name.
Can I monitor what network requests my extensions make?
VS Code does not provide a built-in way to monitor individual extension network activity. However, you can use external tools to observe outbound traffic from the VS Code process.
# macOS: monitor network connections from VS Code
lsof -i -n -P | grep "Electron"
# Linux: use ss to check VS Code's network connections
ss -tnp | grep codeFor deeper analysis, tools like Little Snitch (macOS) or Glasswire (Windows) can alert you when VS Code connects to unfamiliar domains. This will not prevent an attack, but it can help you detect one in progress.
Do other editors like JetBrains IDEs or Neovim have the same problem?
Every editor with a plugin system faces some version of this risk. JetBrains IDEs run plugins in the JVM with similar levels of access. Neovim plugins written in Lua or VimScript can also access the file system and spawn processes.
The difference is scale. VS Code has the largest extension marketplace (over 50,000 extensions) and the largest user base, making it the highest-value target for supply chain attacks. The same audit principles from this guide apply to any editor with a plugin ecosystem: review what you have installed, remove what you do not use, and verify the source.
VS Code extension security is not about paranoia. It is about recognizing that every extension you install is running code on your machine with access to your files, credentials, and network, then making deliberate decisions about which ones you trust.
Run the code --list-extensions audit today. Remove anything unused. Harden your VS Code settings. Set a quarterly reminder. If you work on a team, get an approved extensions list into your repository. That is the whole job.
For related security practices, see our guide on GitHub Actions security hardening, which covers the CI/CD side of the same supply chain problem. If your extensions include dependency scanners, pair them with DepScan to catch vulnerable packages in your package.json.
Related Articles
How to Use Environment Variables in Next.js (Without Leaking Them to the Browser)
Learn how to use .env files in Next.js correctly. Understand NEXT_PUBLIC_, avoid common mistakes, and set variables in Vercel and Cloudflare.
npm Scripts You're Probably Not Using (But Should Be)
pre/post hooks, cross-env, npm-run-all, argument passing, and built-in variables: the npm script patterns developers Google one at a time, in one place.