When a developer discovers a compromised VS Code extension, the playbook is straightforward: uninstall the extension, revoke the OAuth token, rotate your passwords. Done.
Except it isn't. At least, not anymore.
Knostic's security research team has identified malicious VS Code extensions abusing VS Code's shared GitHub authentication model, distinguished by a persistence mechanism that survives standard incident response. These extensions are designed not just to steal your credentials, but to plant a backdoor into your GitHub account that survives token revocation, password rotation, and even uninstalling the extension itself. By the time you realize something is wrong, the attacker may already have established persistent Git access to every repository you own... and revoking your token does nothing to stop them.
Here's how it works, what we found in the wild, and, critically, what you need to check right now even if you've never heard of these extensions.
VS Code has a built-in authentication system that lets extensions request access to your GitHub account. When you install GitHub Copilot or the GitHub Pull Requests extension, VS Code stores a GitHub OAuth session locally. Any other extension can then silently request access to that same session, with no visible prompt to the user, using a single API call:
vscode.authentication.getSession('github',['read:user','user:email','repo','workflow'],{silent:true})
If you have any GitHub extension already installed, this call may succeed, returning a live OAuth token with the broadest possible scopes — without you ever seeing a dialog box. The token grants full read and write access to all your repositories, including private ones.
This is not a bug in a single extension. It's a design characteristic of VS Code's shared authentication model, and it means that any extension you install can silently inherit your GitHub credentials.
Separately, security researcher Ammar Askar publicly disclosed a related attack in June 2026, a one-click technique abusing VS Code's webview message-passing to extract tokens from github.dev. While that technique differs from the silent session hijacking used here, both abuse VS Code's shared GitHub authentication model through different mechanisms.
If the silent call fails (no existing GitHub session), the extension falls back to showing an OAuth consent dialog requesting only the repo scope — the minimum needed to access all private repositories. The prompt appears to come from VS Code itself, not from the malicious extension.
While conducting routine threat hunting across the VS Code and OpenVSX marketplaces, Knostic researchers identified two extensions exploiting this technique. Both were discovered through AgentMesh, Knostic's supply chain security platform for AI development tooling.
|
Extension |
Publisher |
Published |
Installs |
Status |
AgentMesh |
|
theme-helper-utils |
pemhkakbh |
June 6, 2026 |
0 |
Removed from Marketplace |
|
|
GHDev Token Steal PoC |
julesgzel |
June 4, 2026 |
0 |
Removed from Marketplace |
Both extensions were analyzed via static code review. Neither accumulated installs before removal, and no victim activity has been confirmed. The behaviors described in this post reflect each extension's designed functionality as observed in source code.
That said, the infrastructure built by theme-helper-utils in particular, server-side SSH keypair generation, a dedicated exfiltration endpoint, evasion against extension-listing diagnostics, reveals operational sophistication that goes well beyond a proof of concept.
Static analysis of theme-helper-utils (SHA256: 62218ea17ee9f369ef16b16fb07856e7b2729b259a55991f3b4047785f702950) revealed the following attack chain, executed entirely on onStartupFinished — meaning it runs automatically every time VS Code opens, with no user interaction required.
|
Step |
Action |
Detail |
|
0 |
800ms startup delay |
Avoids scanners that flag immediate network activity at launch |
|
1 |
Evasion: JSON.stringify patch |
Globally overrides JSON.stringify to substitute the extension's own ID with vscode-pull-request-github in any serialized array — hiding it from diagnostic tools and VS Code's own telemetry |
|
2 |
Silent OAuth token theft |
Requests maximum scopes (read:user, user:email, repo, workflow) with silent: true — no UI prompt, no user awareness |
|
3 |
GitHub account enumeration |
4 parallel API calls: GET /user, /user/orgs, /user/keys, /user/repos (fully paginated — every repository) |
|
4 |
SSH key implantation |
Requests a keypair from the attacker's C2 server, then calls POST /user/keys on the GitHub API to plant the attacker's public key on the victim's account under the title vscode-recovery |
|
5 |
Deep repository scan |
Reads .env, .env.local contents, GitHub Actions secret names, and CI/CD workflow definitions from the 15 most recently active repositories |
|
6 |
Exfiltration |
Single POST to C2: token, identity, all repository metadata, .env file contents, secret names, CI/CD workflow definitions |
OAuth token theft from VS Code extensions is a known risk. What sets this attack apart — and what makes standard incident response insufficient — is step 4: the SSH key implantation.
The diagram below shows why revoking your token closes only half the door.
The attack uses a two-phase approach that appears uncommon in publicly documented VS Code extension malware and represents a notable evolution in persistence tradecraft:
The attacker retains the private key. This means:
Revoke your OAuth token → attacker still has git access via SSH
Rotate your password → attacker still has git access via SSH
Uninstall the extension → attacker still has git access via SSH
The only action that terminates access is explicitly removing the vscode-recovery SSH key from your GitHub account settings.
This persistence mechanism is deliberately designed to survive the standard response. A developer who discovers the compromise, revokes their token, and considers the incident closed is still fully exposed.
|
Data |
Sensitivity |
|
Raw GitHub OAuth token |
CRITICAL |
|
GitHub identity, email, organization memberships |
HIGH |
|
All repository names and permissions |
HIGH |
|
.env and .env.local file contents (plaintext) |
CRITICAL |
|
GitHub Actions secret names (names only — the GitHub API does not return secret values) |
MEDIUM |
|
CI/CD workflow definitions |
MEDIUM |
|
Existing SSH key titles and public keys |
HIGH |
The .env exfiltration is worth emphasizing. In a typical developer environment, .env files contain database credentials, third-party API keys, cloud provider secrets, and internal service tokens. The attack is designed to systematically collect these from the 15 most recently active repositories — not just the current workspace.
Any VS Code or Cursor user may be a viable target if they have:
No additional user action is required. Simply having one of these extensions installed means a malicious extension can silently inherit your GitHub credentials the moment VS Code starts.
Given that GitHub Copilot has tens of millions of users, the potential victim pool for this attack class is very large.
All domains and URLs below are defanged. Replace [.] with . and hxxps[://] with https:// to reconstruct live values.
|
Type |
Value |
|
C2 domain |
github-token-poc[.]app-kvil11[.]workers[.]dev |
|
Keygen endpoint |
hxxps[://]github-token-poc[.]app-kvil11[.]workers[.]dev/keygen |
|
Exfil endpoint |
hxxps[://]github-token-poc[.]app-kvil11[.]workers[.]dev/exfil |
|
SHA256 |
62218ea17ee9f369ef16b16fb07856e7b2729b259a55991f3b4047785f702950 |
|
SHA1 |
0de0efc99f884ae8c087adece74d6229ab4509ec |
|
SSH key title planted |
vscode-recovery |
|
SSH key comment (C2-generated keys) |
implant@poc |
|
Masquerade extension ID |
vscode-pull-request-github |
|
OAuth scopes (silent) |
read:user, user:email, repo, workflow |
|
OAuth scopes (fallback) |
repo |
|
Type |
Value |
|
C2 domain |
ghdevpocdemo[.]julesgzel[.]dev |
|
Exfil endpoint |
hxxps[://]ghdevpocdemo[.]julesgzel[.]dev/api/export-token |
|
SHA256 |
776dc0e5d370cf7dc1461b76526cd7c05ca102a88abf1e2c63f69db8f83654d6 |
|
OAuth scopes (silent) |
read:user, user:email, repo, workflow |
During the review process, Knostic researchers validated the behavior of the C2 infrastructure associated with theme-helper-utils. A request to the root of github-token-poc[.]app-kvil11[.]workers[.]dev returned {"status":"live"}, and the /keygen endpoint was functional, generating valid ssh-ed25519 public keys on request. This confirms the infrastructure was not placeholder or abandoned: the full attack chain was ready to execute against any victim who installed the extension.
Multiple requests to /keygen produced distinct keypairs, consistent with the static analysis finding that each victim receives a unique SSH key. All generated keys carried the comment implant@poc, added to the IOC table above. One consequence of per-victim key uniqueness is that there is no reusable public-key fingerprint to hunt across GitHub accounts, each planted key is different, leaving the SSH key title (vscode-recovery) and comment (implant@poc) as the only consistent artifacts. Neither the extension's file hash nor the C2 domain appeared in VirusTotal or any public threat intelligence feed at the time of investigation.
If you have installed any untrusted VS Code extension recently, particularly one published by a random-string publisher account with zero reviews, take these steps in order:
Note: Steps 2–6 are irrelevant if you haven't completed step 1. Revoking the OAuth token alone does not terminate attacker access.
These two extensions represent the beginning of a trend, not an isolated incident. The VS Code extension marketplace processes a high volume of new submissions daily, and the authentication model that enables this attack class is a platform-wide characteristic, not something individual extensions can opt out of.
Knostic's AgentMesh platform monitors the VS Code and OpenVSX marketplaces continuously for extensions exhibiting this behavior. During ongoing marketplace monitoring, we continue to identify newly published extensions exhibiting behavioral and publication patterns that warrant further investigation.
The most effective defense at the individual level is simple: treat VS Code extensions with the same scrutiny you apply to any software you install. Check the publisher, check the install count, check the reviews. A syntax theme with zero installs, published yesterday by an eight-character random string account, should raise the same flags as an unsigned binary from an unknown source.
We will continue publishing findings as we identify them.