Wanctl Securityreport.tagzxia.com
Internal audit · 2026-07-23 · read-only review

Wanctl 安全边界
并不像产品叙事那么干净

这不是后门报告。密码学底座大体正确:E2E TLS、指纹身份、token 哈希入库。 真正的问题在权限模型、Shell 语义、文件根与发布链—— 已配对控制端比“受策略约束的执行器”拥有更大权力。

17Findings filed
#3–#19GitLab issues
3P0 confirmed
NoneHardcoded secrets
3
P0 · 已验证可利用
7
P1 · 条件型高危
6
P2 · 加固项
1
UX · 长效授权缺失

怎么读这份报告

红色 P0 = 动态探针已证实,修复前不建议扩大生产。 P1 多为真实设计缺陷,需要已信任身份或部署失误。 P2 是加固。UX 不是 CVE,但会把人推向 bypass。 未修改业务源码;govulncheck 无可达依赖漏洞。

P0

Critical

已验证边界破坏。已配对控制端即可造成实质代码执行或全权管理。

3
P0-01
#3 P0

普通可信控制端可通过 console_hello 提升为持久 bypass 管理员

已配对控制端 ≈ 设备管理员。

原理

普通会话与 console_hello 共用同一套 fingerprint 信任判断。任意 known_clients 中的控制端都可进入控制台,调用 mode_set 把策略切到持久 bypass,并获得改规则、批命令、信/撤控制端、读日志、开关 LAN 中继等能力。客户端自报的 Role/Name/Label 不可信。

规模

单设备全权接管;若多个控制端共享配对信任,影响面等于所有已信任控制器。

影响

策略形同虚设。MCP/CLI 凭据一旦泄漏,不是“只能跑批准命令”,而是接近本机 shell 管理权。

证据 / 修复

动态探针:ordinary-controller 经 console_hello 成功持久化 bypass。代码:internal/agent/agent.go handleSession / authorize / handleConsoleRPC。

拆分 known_clients 与 console admins;console 仅允许独立管理员/Portal capability;mode_set/rule_add/pair_decide 二次授权。

P0-02
#4 P0

命令前缀规则可被追加 Shell 操作符绕过

批准 git status ≠ 只允许 git status。

原理

MatchCommand 使用前缀匹配:c == p || HasPrefix(c, p+" ")。执行路径是 sh -c / PowerShell -Command 的完整 shell 源码,不是结构化 argv。因此 git status && curl|sh、git status; rm -rf 等都会命中已批准前缀。

规模

所有“带参数扩展能力”的已记忆规则;任一批准命令都可能变成任意命令载体。

影响

审批边界失效,直接 RCE。用户以为“白名单很严”,实际只锁了字符串开头。

证据 / 修复

MatchCommand("git status", "git status && ...") == true。policy.go + server/shell.go。

默认 exact match;或解析 executable+argv;拒绝未解析的 ; && || | ` $() <> 等组合符。

P0-03
#5 P0

cwd 字段可注入 Shell 命令绕过审批

工作目录被拼进 shell,变成第二条命令。

原理

withCwd 生成 cd "${cwd}"; ${cmd}。策略主要校验 Command,不约束 cwd 语义。恶意 cwd 如 "; id; #" 在已批准 true 时仍执行副作用。

规模

所有走 cwd 的远程执行路径;Windows/POSIX 字符串拼接双平台均中。

影响

经典命令注入。审批 UI 显示 benign 命令,实际已执行攻击载荷。

证据 / 修复

探针:cwd="; printf owned > /tmp/hit; #" + approved true 成功。agent.go withCwd。

删除字符串拼接;exec.Cmd.Dir;cwd canonicalize/存在性/白名单;持久 shell 用安全 cd 协议。

P1

High

真实设计缺陷。通常需要已信任身份、错误部署或供应链条件,但后果大。

7
P1-01
#6 P1

文件根目录词法校验,符号链接可逃逸

允许目录只是路径前缀,不是真实根。

原理

Within 只做 filepath.None 词法判断;Open/OpenFile 跟随 symlink。/safe/link -> /etc 时,/safe/link/passwd 词法合法、实际越权。

规模

凡授予文件读写且攻击者能在允许树内放置/利用 symlink 的场景。

影响

目录沙箱失效,可读/写预期外路径。

证据 / 修复

动态探针经 /allowed/link/file 写入落在根外。policy.Within + server/files.go。

os.Root / openat 根约束;拒绝 symlink/设备/FIFO;注意 TOCTOU。

P1-02
#7 P1

Portal SSO 身份映射可碰撞并覆盖原用户

邮箱本地部分清洗后当 namespace,冲突就覆盖。

原理

信任 X-Auth-Request-Email 等头;namespace 由本地部分 toLower + 非法字符变 - 派生;ON CONFLICT DO UPDATE 重绑 feishu_open_id。alice.smith / alice_smith / 跨域同名可撞车。

规模

多租户 Portal;代理未剥客户端身份头时更严重。

影响

原用户失权或租户被接管;体验上是“账号乱了/设备不见了”。

证据 / 修复

portal.go 读头;relay/admin.go 清洗与冲突更新。

不可变 SSO subject 做主键;namespace 仅显示名且冲突失败;代理重写身份头;后端私网/mTLS。

P1-03
#8 P1

自更新/安装器无签名,Relay 沦陷可全网 RCE

更新通道即代码执行通道。

原理

从 Relay 下载后直接可执行/安装;无 hash、签名、大小上限。E2E 业务加密不覆盖更新投毒。Unix 路径可能经 sudo。

规模

全舰队所有在线设备。

影响

供应链单点:Relay/域名/TLS 终止/发布目录任一沦陷 → 任意程序下发。

证据 / 修复

update.go、relay/dist.go 无验签。

签名 manifest + 内置公钥;分发端不持私钥;轮换/撤销;大小上限。

P1-04
#9 P1

Relay admission token 放在 URL query

长期凭据出现在最容易被记日志的位置。

原理

/dial?token=、/h/poll?token= 等;默认 LAN 还有 ws://。URL 进 access log、APM、WAF、截图、复制粘贴。

规模

所有控制器与设备接入路径;明文 LAN 观察者直接可见。

影响

token 泄漏后可接入设备命名空间。

证据 / 修复

client.go / agent.go / httpconn.go。

Authorization Bearer 或短时 ticket;wss;禁止 query 记凭据。

P1-05
#10 P1

MCP rebind 是明文 token 的 Base64

给模型的“会话恢复码”≈ 长期 token。

原理

base64(namespace\0token) 无加密/签名/过期;decode 后 saveLogin 未强制以 Relay 真实 namespace 为准。logout 不吊销服务端 token。

规模

所有 MCP/AI 会话历史与调试记录。

影响

凭据进模型上下文;可重放;可伪造 namespace 影响身份派生。

证据 / 修复

mcp/server.go encode/decode rebind。

短时签名 rebind;不回显 raw token;Relay 校验 namespace;可吊销。

P1-06
#11 P1

ACL perms 字段只展示不执行

UI 写 read-only,协议仍全连接。

原理

AllowedDial 只查 ACL 是否存在,不看 perms。exec/read/write 无服务端强制。前端限制可被 CLI/MCP 绕过。

规模

所有共享设备/跨 namespace 授权。

影响

产品信任破产;最小权限叙事不成立。

证据 / 修复

relay/pgstore.go AllowedDial;全仓无 perms 执行点。

不可伪造 capability;设备侧按消息类型强制;console 不得由普通 ACL 授予。

P1-07
#12 P1

缺请求体/超时/任务边界,可被资源耗尽

有 token 就能把服务和设备拖垮。

原理

io.ReadAll 无上限;HTTP 无 Read/Write/Idle timeout;job 无限并发、输出全进内存、无取消。

规模

Relay 多租户与单设备 Agent 同时受影响。

影响

OOM、卡顿、任务堆死——直接伤体验,也是 DoS。

证据 / 修复

relay/http.go、agent/jobs.go、main/mcp 缺超时。

MaxBytesReader;完整超时;job 有界缓冲/超时/取消/并发上限。

P2

Medium

加固与运营风险。日常可跑,扩大生产前应消化。

6
P2-01
#13 P2

事件日志永久记录完整命令与路径

排障友好,密钥也落盘。

原理

events.jsonl 记完整 command/cwd/path;普通可信控制端与共享用户可远程读;无脱敏/轮转。

规模

设备本地审计面 + 远程可读面。

影响

token/password/env 持久化;合规与横向移动素材。

证据 / 修复

eventlog.go + KindLogs。

脱敏;参数摘要;日志独立授权;轮转配额。

P2-02
#14 P2

Portal 缺 CSRF/Origin/CSP/frame 防护

审批控制台按“内网页面”在做。

原理

无 CSRF token、Origin 校验、CSP、frame-ancestors;Markdown 链接未限 scheme;/whoami 回显全部头。

规模

依赖 SSO Cookie 属性;可 iframe/跨站时放大。

影响

诱导信任控制端、批命令、切 bypass;点击型 javascript: 链接。

证据 / 修复

portal 前端与 handler 缺浏览器边界。

CSRF+Origin;CSP/frame-ancestors;严格 method;URL scheme 白名单;移除 whoami 头回显。

P2-03
#15 P2

文件上传非原子且无大小/类型校验

一开传就截断目标文件。

原理

O_TRUNC 后流式写;不校验 Size;断连半文件;不拒特殊文件。

规模

所有远程写文件路径。

影响

可靠性差:网络抖动即可写坏配置/产物。

证据 / 修复

server/files.go。

临时文件 + fsync + rename;字节校验;上限;仅普通文件。

P2-04
#16 P2

TOFU 首次无确认,设备键忽略 owner namespace

第一次见证书就钉死;同名可混。

原理

首次设备证书直接持久化;固定键主要用 device name,弱化 owner namespace。

规模

首次配对与跨 namespace 同名设备。

影响

抢注/连错设备难发现。

证据 / 修复

transport/handshake.go、client keying。

首次指纹确认/配对码;key=ns+device+fp;证书变化显式 re-pin。

P2-05
#17 P2

编译期内置 Portal 指纹成 fleet 根信任

一个 Portal 私钥管所有默认设备。

原理

默认预信任硬编码生产 Portal 指纹;控制台拒绝撤销;缺双密钥轮换与紧急吊销。

规模

默认部署的全部 Agent。

影响

根密钥事故时难收场;自建部署也携带公司信任。

证据 / 修复

config.go + main 预信任。

根 CA 级管理;重叠期轮换;紧急撤销;自建默认最小化信任。

P2-06
#18 P2

镜像与安装分发供应链偏弱

能跑,但发布链不够硬。

原理

Alpine 3.20 常规支持已结束;可变 tag、默认 root;安装器信 Host/X-Forwarded-Proto;文档含内部元数据。

规模

镜像构建与安装入口。

影响

过期基础镜像与 Host 注入/缓存污染风险;运维债。

证据 / 修复

Dockerfile、relay/dist.go、docs。

受支持镜像+digest;非 root;canonical URL;CI 扫描/SBOM;文档脱敏。

UX

Product

体验债,不是 CVE。处理不好会把人推向更不安全的用法。

1
UX-01
#19 UX

每次授权都要验证码,缺长效分层方案

不是漏洞,是安全产品化缺口。

原理

所有授权同等强度验证码,无可信设备/短会话/refresh 分层;高频 AI/CLI 被反复打断。

规模

日常操作路径。

影响

体验差 → 用户倾向开 bypass 或绕过流程,反而抬高真实风险。

证据 / 修复

产品行为与审批流观察。

设备绑定+短 access/可吊销 refresh;低风险免打扰,高风险 step-up;可查可撤会话。