Feast Registry gRPC Unauthenticated RCE via dill.loads — CVE-2026-56121
by Caio Fabrício (BiiTts) — [github.com/BiiTts](https://github.com/BiiTts) · 2026-07-05
- Severity
- Critical
- CVE
- CVE-2026-56121
- Category
- misc
- Affected product
- Feast (open-source feature store) registry gRPC server
- Affected versions
- Feast < 0.63.0 (fixed in 0.63.0)
- Disclosed
- 2026-07-05
- Patch status
- patched
Archive entry
intelseclab/poc-archiveMetadata
| Field | Value |
|---|---|
| Date Added | 2026-07-05 |
| Last Updated | 2026-06-30 |
| Author / Researcher | Caio Fabrício (BiiTts) — github.com/BiiTts |
| CVE / Advisory | CVE-2026-56121 |
| Category | misc |
| Severity | Critical |
| CVSS Score | 9.8 (AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H, per source repository) |
| Status | PoC |
| Tags | feast, feature-store, dill, pickle, deserialization, grpc, unauth-rce, mlops |
| Related | N/A |
Affected Target
| Field | Value |
|---|---|
| Software / System | Feast (open-source feature store) registry gRPC server |
| Versions Affected | Feast < 0.63.0 (fixed in 0.63.0) |
| Language / Platform | Python 3 (Feast SDK / registry server) |
| Authentication Required | No — shipped default config is auth: type: no_auth; deserialization also runs before any authorization check even when auth is enabled |
| Network Access Required | Yes — reach the registry gRPC port (default 6570) |
Summary
Feast’s registry gRPC server deserializes the user-defined function (UDF) body of an OnDemandFeatureView with dill.loads() (a pickle superset) the moment a spec is received via the ApplyFeatureView RPC — before any permission check runs. Because the default deployment ships auth: no_auth, any client that can reach the registry port can submit a crafted ApplyFeatureView request containing a malicious pickle in user_defined_function.body and achieve arbitrary OS command execution on the registry host. The PoC reproduces this end-to-end against feast==0.62.0 inside a Docker lab, confirming command execution via a __reduce__-based os.system gadget.
Vulnerability Details
Root Cause
sdk/python/feast/registry_server.py’s ApplyFeatureView handler calls OnDemandFeatureView.from_proto(...) to parse an incoming feature view spec before calling assert_permissions_to_update(...). from_proto in turn calls into sdk/python/feast/transformation/pandas_transformation.py (and python_transformation.py), which does udf = dill.loads(user_defined_function_proto.body) on the attacker-controlled body bytes. Since dill is a pickle superset, unpickling attacker bytes invokes the pickle __reduce__ machinery, which can call arbitrary callables (e.g. os.system) as a side effect of deserialization. The ordering bug (deserialize-then-authorize) means the code executes regardless of the authorization outcome, and the default no_auth configuration means there is no authorization check to begin with.
Attack Vector
- Attacker crafts a Python object whose
__reduce__method returns(os.system, (cmd,))and pickles it withpickle.dumps(...). - Attacker builds an
ApplyFeatureViewRequestprotobuf message with anon_demand_feature_viewwhosespec.feature_transformation.user_defined_function.bodyis set to the malicious pickle bytes (mode="pandas"). - Attacker sends the request over an insecure gRPC channel to the registry server’s
RegistryServer.ApplyFeatureViewRPC (default port 6570) — no credentials required. - The server’s
from_protopath callsdill.loads()on the body before checking permissions; the pickle’s__reduce__fires, runningos.system(cmd)on the registry host. - The RPC subsequently errors out (the unpickled object,
0, is not a valid callable UDF), but the command has already executed server-side — the PoC verifies this by having the command write output to a file on the target host.
Impact
Anyone able to reach the Feast registry gRPC port obtains arbitrary OS command execution as the registry service account, resulting in full compromise of the feature store and everything it is wired to — offline/online stores, other registries, and any cloud credentials available to that process. Feast registries are frequently exposed inside ML platforms for SDK clients to call, widening the practical attack surface.
Environment / Lab Setup
Target: Docker container running feast==0.62.0 registry gRPC server (feast serve_registry), port 6570 exposed, default auth: no_auth config generated by `feast init` / `feast apply`.
Attacker: Python 3 with `grpc` and `feast==0.62.0` installed (for the generated protobuf stubs); network reachability to target:6570.
Proof of Concept
PoC Script
See
exploit.pyin this folder.
| |
The script builds an ApplyFeatureViewRequest whose on_demand_feature_view.spec.feature_transformation.user_defined_function.body contains a pickled object with a __reduce__-based os.system gadget, then sends it unauthenticated to the target’s registry gRPC endpoint via grpc.insecure_channel. The RPC ultimately raises an error (the deserialized “UDF” is not callable), but the command has already run during dill.loads().
Detection & Indicators of Compromise
[*] 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.
Signs of compromise:
ApplyFeatureView/ApplyMaterializationRPCs to the registry where the incomingOnDemandFeatureView.user_defined_function.bodydid not originate from a trusted SDK client.- Registry server process (
feast serve_registry) spawning unexpected child shells or processes. - Errors in registry logs of the form
"... is not a module, class, method, or function"immediately following anApplyFeatureViewcall, indicating a non-callable object was unpickled as a UDF. - Unexpected files/output appearing on the registry host filesystem.
Remediation
| Action | Detail |
|---|---|
| Primary fix | Upgrade to Feast ≥ 0.63.0, which threads a skip_udf flag through from_proto so the registry server no longer deserializes the UDF body of incoming specs. |
| Interim mitigation | Never expose the registry gRPC port to untrusted networks; enable auth (oidc/kubernetes) as defense in depth — note auth alone is not sufficient on < 0.63.0 since deserialization precedes the authorization check; monitor/alert on ApplyFeatureView calls carrying unexpected UDF bodies. |
References
Notes
Mirrored from https://github.com/BiiTts/CVE-2026-56121-Feast-Unauth-RCE on 2026-07-05.
| |