mcp-shell has a Secure Mode Allowlist Bypass via Git Shell Alias
Published Aug 25, 2026 · Updated Nov 3, 2026
Original summary
Normalized public record · Updated Nov 3, 2026
mcp-shell has a Secure Mode Allowlist Bypass via Git Shell Alias
Publisher and source text is retained separately from QFinch interpretation.
QFinch assessment
mcp-shell's "secure mode" is designed to restrict command execution to an allowlist of executables defined in security.yaml. The default configuration includes /usr/bin/git. The security validator in security.go blocks common shell metacharacters (|&;<>(){}[]$\) but omits !, which is the prefix Git uses to execute shell aliases (alias.NAME=!CMD). An attacker who can invoke the shellexec MCP tool can pass /usr/bin/git -c alias.pwn=!<arbitrary-command> as the command argument, bypassing all validation and achieving arbitrary OS command execution as the mcp-shell process user. The default Docker image runs as mcpuser (UID 1000) with Git installed and secure mode enabled, making this exploitable in the default deployment with no authentication required.
Potential impact
This is an OS Command Injection vulnerability (CWE-78). Any entity that can issue an MCP tools/call request to a mcp-shell instance running with the default Docker configuration can execute arbitrary OS commands as the mcpuser process account (UID 1000) inside the container. The default Docker deployment sets MCPSHELLSECCONFIGFILE=/etc/mcp-shell/security.yaml, installs git, and runs as mcpuser. The shellexec tool requires no additional authentication beyond MCP connectivity. "Secure mode" is explicitly marketed as the mechanism preventing command injection; this bypass nullifies that protection entirely. Impacted parties: - Users and operators who deploy the default mcp-shell Docker image and expose it to MCP clients (directly via stdio, or via an MCP bridge/proxy over the network). - AI agent systems that integrate mcp-shell as a tool provider, where a compromised or malicious LLM prompt could supply the exploit payload as the command argument.
Technical context
The vulnerability is a classic OS Command Injection (CWE-78) in the shellexec MCP tool handler. The data flow from attacker input to shell execution is: 1. main.go:89-91 — The MCP tool schema exposes a required string parameter command with no server-side type constraints. 2. main.go:102 — shellexec is bound to shellHandler.handle. 3. handler.go:34 — The handler reads the attacker-controlled value: command, err := request.RequireString("command"). 4. handler.go:49 — The command string is passed to h.validator.validateCommand(command). 5. security.go:136 — containsShellMetacharacters checks for |&;<>(){}[]$\ but ! is absent from the blocked set. 6. security.go:147-149 — containsDangerousShellConstructs also does not include !. 7. security.go:85-96 — /usr/bin/git matches AllowedExecutables; no per-argument policy exists for Git. The blockedpatterns list in security.yaml:35 is empty ([]). 8. handler.go:59 — The fully validated (but unsafe) command is forwarded to h.executor.execute. 9. executor.go:149-163 — parseCommand splits the string with strings.Fields; exec.CommandContext(ctx, executable, args...) is called with executable="/usr/bin/git" and args=["-c", "alias.pwn=!touch", "pwn", "/tmp/target"]. 10. executor.go:199 — cmd.Run() launches git. Git interprets -c alias.pwn=!touch as a runtime configuration entry, defining the alias pwn as the shell command touch. When Git resolves the subcommand pwn, it triggers the shell alias: sh -c 'touch "$@"' /tmp/target, creating the file. The root cause is the missing ! in the metacharacter blocklist and the absence of any per-executable argument policy that would prevent Git's -c alias.=! pattern. Incriminated source locations: - security.go:136 — metacharacter set missing ! - security.go:147-149 — containsDangerousShellConstructs missing ! - security.yaml:27 — /usr/bin/git in allowedexecutables - security.yaml:35 — blockedpatterns: [] - executor.go:149-163,199 — direct exec.CommandContext invocation with unsanitized Git arguments
Evidence: public source recordsAffected products
| Affected package, product or range | Fix status |
|---|---|
| Consult the referenced vendor advisory for affected versions. | Consult source advisory |
Matching a version is only one part of assessing exposure. QFinch has not assessed your environment on this public page.
Remediation
Apply the vendor-supported fixed release or mitigation, then verify the affected component is no longer reachable.
- Confirm the affected product and reachable code path exist in your environment.
- Apply the vendor-supported patch or mitigation from the primary advisory.
- Rescan the exact deployed revision and retain verification evidence.
Evidence coverage
- SSVC priority
- MEDIUM
- Confidence
- Not available
- Aliases
- None reported
Scores appear only when corresponding evidence exists. Missing data is never interpreted as zero risk.
Sources and record history
Record history
Published Aug 25, 2026 · Last refreshed Nov 3, 2026