fix(mcp): reject requires entries with shell metacharacters - #259
Merged
Conversation
`requirementsMet` checks each `requires` executable with `command -v <bin>` run under `/bin/sh`. `bin` comes straight from the team repo's mcp.yaml, so a value like `npx; rm -rf ~` is passed to the shell and executed — a command injection triggered on any member's machine during `teamai pull` / `teamai mcp inject`. Validate each name against `^[A-Za-z0-9][A-Za-z0-9._-]*$` before the shell ever sees it. A real executable name has no shell metacharacters, so anything else is rejected with an invalid-name skip reason rather than run. Legitimate `requires` (e.g. `npx`) are unaffected. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
5 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
requirementsMetinsrc/mcp-reconcile.tsverifies eachrequiresexecutable via:bincomes directly from the team repo'smcp/mcp.yaml. Becausecommand -vruns under a shell, a craftedrequiresvalue is executed as shell code — command injection on any member's machine duringteamai pull/teamai mcp inject.Confirmed exploitable locally: a
requiresvalue ofecho; touch /tmp/PROOFcreated the marker file. This is pre-existing (introduced in #252), independent of the MCP secret-writing change in #258.Change
Validate every
requiresname against^[A-Za-z0-9][A-Za-z0-9._-]*$before it reaches the shell. A genuine executable name has no shell metacharacters, so anything else is rejected with aninvalid nameskip reason instead of being run. Legitimate entries likenpxare unaffected.Kept the existing
command -vmechanism (portable across the shells teamai targets) rather than switching towhich/where, since the whitelist already removes the injection surface.Test Plan
npx tsc --noEmit— no errorsnpx vitest run— 1815 passed (added a test asserting a metacharacter-ladenrequiresis skipped and its injected command never runs)npm run build— successrequires: ["echo; touch /tmp/E2E_INJECTION_PROOF"]→ serverskipped(invalid name), marker file NOT createdrequires: ["npx"]→ serveraddednormally🤖 Generated with Claude Code