About Shell Server
Shell Server is an MCP server published by AcE77505 in the Developer Tools category: aRM64 静态 零依赖 MCP Shell 服务器.
The repository has 10 stars and 0 forks, with the last commit 10 days ago. Recent commit activity is the strongest signal that reported issues will get attention.
Install
git clone https://github.com/AcE77505/mcp-shell-serverThis server has no ConduID identity, so agent calls to it are not receipted. Pin the version you install and review the source before granting it credentials.
Ask AI
Ask AI about Shell Server
Powered by Claude · Grounded in docs
Security checks
Static checks derived from the repository 6 days ago. Heuristics on the source, not an audit.
- ✓README presentThe repository ships documentation.
- ✓License declaredUsable under a stated license.
- !Tests presentNo tests found. Behaviour changes may go unnoticed between versions.
- !Dependencies pinnedNo lockfile. Installs can pull different code over time.
2 checks have not been run yet.
Releases
README
MCP Shell Server
轻量级 MCP Shell 服务器 — JSON-RPC 2.0 / ARM64 静态 / 零依赖
- MCP 协议
2025-11-25,Streamable HTTP,入口POST /mcp - 单文件 C++11,pthread 多线程,无第三方依赖
工具
| 工具 | 说明 |
|---|---|
shell |
执行命令,返回 pid / stdout / stderr / exit_code / timed_out;可选 timeout(秒) |
status |
列出所有终端,含 mine 标记 |
stop |
停止命令(支持 pid 参数或仅停自己的) |
reset |
复位服务端 |
执行与超时
shell 的 timeout 参数单位是秒,默认不设置:
| 取值 | 行为 |
|---|---|
| 省略(不传) | 不设超时,命令一直执行到退出 |
0 或负数 |
同上,不设超时 |
N > 0(可带小数,如 0.5) |
到点后向整个进程组发 SIGKILL,返回已收集到的输出,timed_out: true、exit_code: -1 |
- 回收子进程的等待是有界的(SIGKILL 后再等最多 2 秒),不会因为进程卡在不可中断状态把请求线程永久挂住。
- stdout / stderr 是两条独立管道,任一路暂时无数据(
EAGAIN)不算读到结尾;两路都到 EOF 且子进程已退出才算完成,所以大输出(>64KB)不会被截断。 - 相反地,如果命令把子进程留在后台且它继承了 stdout/stderr(例如
cmd &没重定向),管道不会关闭,本次调用会一直等到那个后台进程退出。这种场景请写成cmd >log 2>&1 &,或显式传timeout。 status的count与terminals数组长度一致;命令表会自动清理已结束的表项,历史命令再多也不会停止跟踪新命令。
HTTP 层限制
单个请求:两次读之间最多等 5 秒(HTTP_IDLE_MS),整个请求(请求行 + 头 + body)最多 30 秒(HTTP_TOTAL_MS)。超时直接回 408 Request Timeout 并关闭连接,避免慢速喂数据的连接长期占用线程。
快速开始
./mcp-shell-server # 监听 0.0.0.0:8080
./mcp-shell-server -p 9000 # 指定端口
./mcp-shell-server -f # 8080 被占用时,先踢掉占用进程再启动
./mcp-shell-server -p 9000 -f # 指定端口 + 踢掉该端口占用者
客户端地址:http://<ip>:<port>/mcp
参数
| 参数 | 说明 |
|---|---|
-p, --port PORT |
监听端口,默认 8080(1–65535) |
-f, --force |
端口被占用(EADDRINUSE)时,先踢掉占用者,再在该端口启动 |
-h, --help |
用法帮助 |
退出码:-h 返回 0;参数非法、端口收回失败或 bind 失败返回 1;正常启动后常驻。
安全模型(务必先读)
本服务会把收到的命令原样交给 execl("/bin/sh", "sh", "-c", cmd, NULL) 执行,并以服务器进程的身份运行(root 用户可以启动服务器,因此命令也会以 root 用户执行)。
“能执行任意命令”是本项目的功能本体,不是缺陷——对任意命令做“校验/净化”在逻辑上不成立(同类 shell MCP 服务均如此),因此本项目没有命令白名单,也不打算加。
同时,当前默认配置没有任何访问控制:
| 事实 | 说明 |
|---|---|
默认监听 0.0.0.0 |
同一局域网内任何主机都能访问 |
| 无认证 | 不需要 token/cookie/session,也不需要先 initialize,直接 POST /mcp + tools/call shell 即可执行 |
CORS 为 Access-Control-Allow-Origin: * |
任意网页来源都放行,且攻击页还能读到命令输出;OPTIONS 预检返回 * + Allow-Headers: * |
不校验 Content-Type |
text/plain 也能触发执行,属浏览器“简单请求”,连预检都不需要 |
不校验 Origin |
浏览器“投毒网页驱动执行”(CSRF 式 drive-by)在本机/局域网内可行 |
实测(临时实例):不带任何认证头、不 initialize、带 Origin: http://evil.example 的 POST /mcp + tools/call shell 返回 200,并成功执行 echo PWNED uid=$(id -u),输出就是服务进程的 uid。
建议
- 只在可信环境里运行:本机回环,或你自己的、可信任的局域网。不要把端口暴露到公网、做端口转发、或在公共 Wi-Fi 下开启。
- 需要更强的边界时,请自行加一层:只绑回环(当前版本没有
-H,可用 iptables/端口转发或自行改sin_addr)、或用反向代理加 token 校验。 -f(踢掉占用者)只是个便利功能,不是安全机制。- 服务以哪个用户启动,命令就以哪个用户执行;以 root 启动时一旦被触发,影响面相当于整台主机失守。
安全边界与 issue 政策
使用前提(硬性):本服务只在完全受信的运行环境下使用 —— 本机回环,或你自己完全掌控且可信的局域网。不满足该前提的部署方式不在支持范围内(包括但不限于:映射到公网、端口转发、公共 Wi-Fi、共享/不可信网络,以及让不可信页面能访问到该端口的场景)。
因此以下报告不作为缺陷处理(按设计 by design,不开工):
- “命令注入(CWE-78)”“缺少输入校验/命令白名单” —— 执行任意命令是本项目的功能本体,无法“校验”;
- “默认绑
0.0.0.0”“缺少认证/授权”“CORS*” —— 已在上一节列为已知、已文档化的暴露面,需要更强边界请自行加一层(只绑回环 / 反代加 token); - 以上前提下造成的任何损失(含 root 命令被执行) —— 风险自负。
我们只处理针对当前源码可复现的具体缺陷:崩溃、内存/越界问题、逻辑错误等。提交 issue 前请先读本节与上一节,并给出最小 PoC + 版本/commit;否则会被直接引用本节关闭。
端口占用(-f)
Android 上 lsof 常常看不到占用者,-f 不依赖任何外部命令(不用 lsof/netstat/fuser/ss),自己找:
- 从
/proc/net/tcp与/proc/net/tcp6里找 本地端口 == PORT 的 LISTEN socket inode(没有 LISTEN 时退一步看其它已 bind 状态,忽略 TIME_WAIT/CLOSE); - 扫描
/proc/<pid>/fd中的socket:[inode]定位持有者(日志里打印 pid + cmdline); - 对持有者发 SIGTERM,最多等约 1.5s 优雅退出,仍在则 SIGKILL;
- 端口释放后重新
bind(),成功即正常启动。
成功时日志形如:
[I] port 8080 is busy, -f: killing the holder(s)
[I] SIGTERM -> pid 12345 (./mcp-shell-server)
[I] port 8080: holders=1 killed=1 skipped=0 denied=0
[I] === MCP Shell Server ===
[I] Port 8080 EP: POST /mcp
踢不掉时会直接说原因:
| 日志 | 含义 |
|---|---|
no permission to kill pid N / cannot signal ... permission denied, need root |
权限不足,需要 root 运行 |
held by this process tree (pid N ...): nothing killed, start me from another parent |
占用者属于本进程树,一个进程也不会杀(见下) |
cannot attribute holder pid N: nothing killed |
读不到祖先链,保守起见不杀 |
no owning process is visible (permission?) |
看不到持有者(权限或 /proc 受限) |
port N is still in use after -f |
收回失败,端口仍被占用(返回 1) |
为什么“占用者属于本进程树就不杀”:本服务器 fork 命令时监听 fd(fd 3)会被每个命令子进程继承,所以同一端口 socket 的持有者总是“服务器 + 它的命令子进程”这棵树。如果其中任何一个是你(新实例)的祖先,真正的占用者也在同一棵树里,杀其它持有者既不能释放端口、还会误杀无关命令。这种情况请从另一个父进程(例如终端)启动,或先停掉旧实例。
自测
tests/里的脚本都是纯 Python 3(仅标准库),直接POST /mcp:timeout_1.py…timeout_4.py:timeout语义、EAGAIN/EOF、大输出、408、stop与命令表。需要先起两个实例(新旧各一,脚本顶部的NEW/OLD地址自行修改)。live_check.py:对单个运行中实例做超时 / 管道 EOF / 分段输出 / 两路大输出的端到端回归(改脚本里的URL)。bg_pipe.py:后台子进程占着 stdout/stderr 时调用会等待的对照用例。slowloris.py:慢速发头,验证 30 秒后返回408。check_status_esc.py/check_status_nl.py:命令里含引号、反斜杠、换行时status的 JSON 合法性。
编译
g++ -std=c++11 -O2 -static -o mcp-shell-server mcp-shell-server.cpp -lpthread
交叉编译到 ARM64 设备时,用任一 aarch64 工具链加 -static 即可(不需要 NDK):
aarch64-linux-musl-g++ -std=c++11 -O2 -static -o mcp-shell-server mcp-shell-server.cpp -lpthread
变更
- 2026-10-19:
status的cmd字段改为完整 JSON 转义:双引号、反斜杠、换行/回车/制表符及其它控制字符都会转义(上一版只转义换行,命令里带双引号或反斜杠时仍会输出非法 JSON,客户端报 Invalid control character 或 Expecting ',' delimiter)。条目改用 std::string 拼装,避免转义后超长被固定缓冲截断。 - 2026-10-19:重启提示:
-f不能从「本服务 fork 出来的命令」里重启自己——该命令进程继承了监听 socket,会被判为“本进程树的持有者”而拒绝接管(日志:held by this process tree)。换二进制时请另开一个 shell 会话(或在别的 tty)先 kill 旧 pid,再执行./mcp-shell-server -f。 - 2026-10-19:修复四类与超时相关的缺陷:①
timeout参数真正生效(原先硬编码 30 秒);缺省不设超时,传入时单位为秒、到时杀掉整个进程组;② 管道读到的EAGAIN不再被当成 EOF(原实现会提前停止读输出,甚至因管道写满而让子进程与等待环节双向卡死);③ 子进程回收不再无限阻塞(SIGKILL 后最多等 2 秒);④ HTTP 请求加上总时长上限 30 秒(超时回 408)。另修:stop的pid只有字符串形式才生效(数字被忽略)、status的count计数错误、命令表满 64 条后不再跟踪新命令。 - 2026-10-07:新增
-f/--force;端口被占用时可自动踢掉占用者后在该端口启动(自实现 /proc 扫描,零外部依赖)。已实测:-p 18080 -f可收回遗留实例占用的端口;占用者属于本进程树时拒绝接管且不杀任何进程。 - 2026-10-07:README 新增「安全模型」章节,明确“任意命令执行是功能本体”,并列出默认无认证/绑
0.0.0.0/CORS*等暴露面、实测结论与使用建议(含对相关 issue 的回应口径);代码未变。 - 2026-10-07:README 新增「安全边界与 issue 政策」:把“只在受信环境运行”定为硬性使用前提,并声明“命令可注入 / 缺少认证 / 绑
0.0.0.0/ CORS*”不作为缺陷处理(删除原先“以后可能加入访问控制”的表述);代码未变。
README fetched from the repository 6 days ago. The original is authoritative.