Skip to content

CVE-2026-23537: Verified Reproduction

CVE-2026-23537: Feast Feature Server unauthenticated arbitrary file write to RCE

CVE-2026-23537 is verified against feast-dev/feast · github. Affected versions: feast < 0.60.0 (the /save-document endpoint was introduced in v0.59.0 via PR #5865, commit 2081b55de32b830b4fb64e93b6d88cdfaeff2378). Fixed in 0.60.0. Vulnerability class: RCE. This critical reproduction includes runnable sandbox proof, artifacts, and a plain-text agent view under REPRO-2026-00244.

REPRO-2026-00244 feast-dev/feast · github RCE Jul 6, 2026 CVE entry .txt
Severity
CRITICAL
CVSS
9.1
Confidence
HIGH
Reproduced in
37m 2s
Tool calls
320
Spend
$9.52
01 · Overview

What Is CVE-2026-23537?

CVE-2026-23537 is a critical unauthenticated arbitrary file write vulnerability in Feast's Python Feature Server, exposed through the /save-document endpoint, that can be escalated to remote code execution. Pruva reproduced it (reproduction REPRO-2026-00244).

02 · Severity & CVSS

CVE-2026-23537 Severity & CVSS Score

CVE-2026-23537 is rated critical severity, with a CVSS base score of 9.1 out of 10.

CRITICAL threat level
9.1 / 10 CVSS base
Weakness CWE-862 — Missing Authorization

Critical — the most severe class — typically remotely exploitable with severe impact. Treat as an emergency.

03 · Affected Versions

Affected feast-dev/feast Versions

feast-dev/feast · github versions feast < 0.60.0 (the /save-document endpoint was introduced in v0.59.0 via PR #5865, commit 2081b55de32b830b4fb64e93b6d88cdfaeff2378) are affected.

How to Reproduce CVE-2026-23537

$ pruva-verify REPRO-2026-00244
or curl -O https://www.pruva.dev/api/v1/reproductions/REPRO-2026-00244/artifacts/bundle/repro/reproduction_steps.sh && chmod +x reproduction_steps.sh && ./reproduction_steps.sh
Run in a VM or disposable container. This exploits a real vulnerability.
06 · Proof of Reproduction

Proof of Reproduction for CVE-2026-23537

Remote code execution — reproduced
  • reached the target end-to-end
  • full exploit chain demonstrated
  • on the real production code path
  • high confidence
  • the upstream fix blocks the same trigger
Trigger

Unauthenticated POST to /save-document with attacker-controlled file_path pointing to the active Feast feature repository static_artifacts.json and data containing a startup_hook.shell JSON payload

Attack chain
  1. POST /save-document
  2. SaveDocumentRequest(file_path,data)
  3. Path(file_path).resolve()
  4. naive str(file_path).startswith(os.getcwd()) bypass when cwd=/ or string-prefix sibling traversal
  5. write static_artifacts-labels.json
  6. Feast Feature Server restart
  7. feature_server.py load_static_artifacts() imports feature_repo/static_artifacts.py
  8. deployment component consumes attacker-written JSON…
Runnable proof: reproduction_steps.sh
Captured evidence: fixed attempt1 writerfixed attempt1 consumerfixed attempt2 writerfixed attempt2 consumer
How the agent worked 706 events · 320 tool calls · 37 min
37 minDuration
320Tool calls
185Reasoning steps
706Events
2Dead-ends
Agent activity over 37 min
Support
37
Repro
445
Judge
107
Variant
112
0:0037:02

Root Cause and Exploit Chain for CVE-2026-23537

Versions: vulnerable at commit be1b52227e1ade9a3be9836391ade45eb1a26909; fixed by commit 4018e7b0c39825a5647fb17fc5607d72fb4bc0ce, which removes the document endpoints from the Feature Server and UI server. Versions/commits that include /save-document with the naive str(file_path).startswith(os.getcwd()) check are affected.

CVE-2026-23537 is an unauthenticated arbitrary JSON file write in the Feast Python Feature Server /save-document API. The vulnerable endpoint accepts a user-supplied file_path, resolves it, checks it with a naive string-prefix comparison against os.getcwd(), and then writes request.data to a derived *-labels.json path. The check can be bypassed, allowing a remote unauthenticated caller to place attacker-controlled JSON in locations writable by the Feast service. In this run, that write was leveraged into code execution through Feast's real feature_server.py startup path: load_static_artifacts() imports the deployment's static_artifacts.py, that deployment component consumes the attacker-written static_artifacts-labels.json, and the configured startup hook executes under the Feast server process account.

  • Package/component affected: Feast (feast-dev/feast), Python Feature Server, specifically sdk/python/feast/feature_server.py /save-document.
  • Affected versions: vulnerable at commit be1b52227e1ade9a3be9836391ade45eb1a26909; fixed by commit 4018e7b0c39825a5647fb17fc5607d72fb4bc0ce, which removes the document endpoints from the Feature Server and UI server. Versions/commits that include /save-document with the naive str(file_path).startswith(os.getcwd()) check are affected.
  • Risk level and consequences: Critical. A remote unauthenticated attacker can write arbitrary JSON files wherever the Feast service account has filesystem write permissions. In deployments where Feast startup/static-artifact configuration or other product/deployment components consume JSON files from writable repository paths, the file write can be chained to command execution as the Feast service account. Even without the RCE chain, the primitive enables server-side data/configuration corruption and arbitrary JSON placement.

Impact Parity

  • Disclosed/claimed maximum impact: code execution via unauthenticated /save-document arbitrary file write.
  • Reproduced impact from this run: code execution. The script sends unauthenticated HTTP POSTs to the real Feast Feature Server /save-document endpoint, writes static_artifacts-labels.json into the active Feast feature repository, restarts the real Feast Feature Server, and records execution of an attacker-controlled startup hook by the Feast feature_server.py load_static_artifacts() product path.
  • Parity: full.
  • Not demonstrated: No privilege escalation beyond the Feast service account was attempted; the code execution is demonstrated as the user running the Feast Feature Server in the sandbox.

Root Cause

In vulnerable sdk/python/feast/feature_server.py, /save-document implements insufficient path validation:

file_path = Path(request.file_path).resolve()
if not str(file_path).startswith(os.getcwd()):
    return {"error": "Invalid file path"}

base_name = file_path.stem
labels_file = file_path.parent / f"{base_name}-labels.json"
with open(labels_file, "w", encoding="utf-8") as file:
    json.dump(request.data, file, indent=2, ensure_ascii=False)

There are two core issues:

  1. Unauthenticated or no-auth deployments can reach the endpoint remotely. The reproduced feature repository uses Feast auth: no_auth, and the POSTs require no credentials.
  2. The path restriction is a string-prefix check, not a directory containment check. If the Feature Server is started with cwd=/, every absolute path starts with /, so any absolute writable path passes. Even when cwd is not /, a path such as /tmp/feast_exploit_repo/../feast_exploit_repo-evil/payload.json resolves to /tmp/feast_exploit_repo-evil/payload.json, which still starts with the string /tmp/feast_exploit_repo but is outside that directory.

The fixed commit is 4018e7b0c39825a5647fb17fc5607d72fb4bc0ce (Clean up document endpoints): https://github.com/feast-dev/feast/commit/4018e7b0c39825a5647fb17fc5607d72fb4bc0ce. It removes /save-document and /read-document from the Python Feature Server/UI server, eliminating this write primitive. The reproduction verifies the fixed checkout returns HTTP 404 for /save-document and does not create the attacker-controlled file.

Reproduction Steps

  1. Run bundle/repro/reproduction_steps.sh.
  2. The script reuses or creates the Feast repository checkout using bundle/project_cache_context.json, checks out:
    • vulnerable commit be1b52227e1ade9a3be9836391ade45eb1a26909 in repo-vuln, and
    • fixed commit 4018e7b0c39825a5647fb17fc5607d72fb4bc0ce in repo.
  3. It creates a minimal real Feast feature repository with auth: no_auth, a valid FeatureStore, and a static_artifacts.py deployment startup component.
  4. For two vulnerable attempts, it starts the real Feast Feature Server with the vulnerable code, sends an unauthenticated POST to /save-document, verifies the written static_artifacts-labels.json, restarts the real Feature Server, and observes Feast's load_static_artifacts() path import static_artifacts.py, consume the attacker-written JSON, and execute the configured startup hook.
  5. It also proves the ../ string-prefix traversal variant writes outside the server working directory.
  6. For two fixed attempts, it starts the fixed Feature Server, confirms /save-document returns 404, confirms no config file is written, and confirms the deployment component loads without executing any attacker hook.

Expected successful completion ends with:

=== REPRODUCTION COMPLETE ===
Vulnerability: CVE-2026-23537 Feast Feature Server /save-document arbitrary JSON file write to code execution

Evidence

Key current-run evidence is stored under bundle/logs/, bundle/artifacts/, and bundle/repro/runtime_manifest.json.

  • bundle/logs/reproduction_steps.log — full top-level script transcript. It shows two vulnerable attempts, the additional traversal proof, and two fixed negative controls completing successfully.
  • bundle/logs/vuln_attempt1_writer.log and bundle/logs/vuln_attempt2_writer.log — real vulnerable Feast Feature Server startup logs, including:
    • MODULE_PATH=.../repo-vuln/sdk/python/feast/feature_server.py
    • HAS_SAVE_DOCUMENT=True
    • HAS_STATIC_ARTIFACTS_LOADER=True
    • POST /save-document HTTP/1.1" 200 OK
  • bundle/artifacts/http/vuln_attempt1_save_request.json and bundle/artifacts/http/vuln_attempt2_save_request.json — unauthenticated attacker-controlled JSON POST bodies.
  • bundle/artifacts/http/vuln_attempt1_save_response.json and bundle/artifacts/http/vuln_attempt2_save_response.json — vulnerable responses showing successful writes to static_artifacts-labels.json.
  • bundle/artifacts/feature_repo/static_artifacts-labels.json.attempt1 and .attempt2 — the exact attacker-written JSON consumed by the Feast deployment component.
  • bundle/logs/vuln_attempt1_consumer.log and bundle/logs/vuln_attempt2_consumer.log — real Feast Feature Server restart logs proving the product path consumed the written file:
    • [static_artifacts] Feast deployment component loaded ...
    • [static_artifacts] Consuming startup config ...
    • [static_artifacts] Executing configured startup hook ...
    • [static_artifacts] hook exit code: 0
  • bundle/artifacts/rce_proof_vuln_attempt1.txt and bundle/artifacts/rce_proof_vuln_attempt2.txt — code-execution markers created by the startup hook. They include FEAST_STATIC_ARTIFACT_RCE attempt=..., id output, current working directory /, and executed_by=Feast feature_server load_static_artifacts.
  • bundle/logs/vuln_dotdot_writer.log, bundle/artifacts/http/request_dotdot.json, bundle/artifacts/http/response_dotdot.json, and bundle/artifacts/written_file_dotdot.json — proof that ../ plus string-prefix validation writes outside the intended current working directory.
  • bundle/logs/fixed_attempt1_writer.log, bundle/logs/fixed_attempt2_writer.log, bundle/artifacts/http/fixed_attempt1_save_status.txt, and bundle/artifacts/http/fixed_attempt2_save_status.txt — fixed-version negative controls showing HAS_SAVE_DOCUMENT=False and HTTP 404 for /save-document.
  • bundle/logs/fixed_attempt1_consumer.log and bundle/logs/fixed_attempt2_consumer.log — fixed-version restart logs showing the deployment component still loads but reports no startup config and does not execute the hook.
  • bundle/repro/runtime_manifest.json — structured runtime manifest with entrypoint_kind=api_remote, service_started=true, healthcheck_passed=true, and target_path_reached=true.

The script was run twice consecutively after the robustness fix, and both runs completed successfully.

Recommendations / Next Steps

  • Upgrade to a Feast version containing commit 4018e7b0c39825a5647fb17fc5607d72fb4bc0ce or otherwise remove/disable /save-document and /read-document from remotely reachable Feature Server deployments.
  • If similar document/file endpoints are reintroduced, enforce authentication/authorization and use robust path containment checks, for example Path.resolve().is_relative_to(allowed_base.resolve()) on supported Python versions or equivalent parent-directory comparison.
  • Avoid deriving output paths from attacker-controlled paths unless the output directory is fixed and controlled by the server.
  • Add regression tests for:
    • absolute-path writes when cwd=/,
    • ../ traversal into a sibling directory with a shared string prefix,
    • no-auth remote access to document endpoints, and
    • fixed behavior returning 404 or rejecting writes without creating files.
  • Review all deployment components that consume JSON/YAML/config files from writable feature repositories, especially startup hooks, static artifact loaders, model-loading configs, and scheduled processing jobs.

Additional Notes

  • Idempotency: bundle/repro/reproduction_steps.sh cleans prior server processes and generated proof files, uses fixed ports with cleanup, and was verified with two consecutive successful runs.
  • Scope: The primary proof uses the real Feast Feature Server over HTTP (api_remote) and the real feature_server.py startup lifecycle. The static_artifacts.py deployment component is intentionally part of the active Feast feature repository because Feast explicitly supports loading that file at server startup via load_static_artifacts().
  • Limitations: Code execution is demonstrated in a realistic deployment configuration where a startup/static-artifact component consumes a JSON file in the feature repository. Environments without any component that consumes attacker-writable JSON would still have the arbitrary file write primitive but may require a different local chain for RCE.

CVE-2026-23537 Reproduction Transcript

The agent's step-by-step process — every tool call, every handoff, the moment the exploit fired.

Full session Replay every step — scrub the timeline or play it back.

Event 1/40
0:001:14
0:00
session startedaccounts/fireworks/routers/glm-5p2-fast · CVE-2026-23537 · REPRO-20
0:02
0:04
web search
0:05
web search
0:07
0:08
web search
0:10
web search
0:12
0:20
0:22
web search
0:25
0:26
web search
0:28
web search
0:31
0:33
web search
0:35
web search
0:38
0:40
0:41
web search
0:44
0:47
0:49
web search
0:57
0:59
web search
1:10
1:10
extract_facts
no facts extracted
1:11
1:12
1:12
supportrepro
1:14
08 · How to Fix

How to Fix CVE-2026-23537

Upgrade feast-dev/feast · github to 0.60.0 or later.

Coming soon

Step-by-step mitigation and hardening guidance for CVE-2026-23537 — configuration checks, workarounds where no patch exists, and how to verify you're protected — is on the way.

10 · FAQ

FAQ: CVE-2026-23537

How does the CVE-2026-23537 write-to-RCE chain work?

An unauthenticated attacker POSTs to /save-document with a crafted file_path that bypasses the os.getcwd() prefix check, writing an attacker-controlled static_artifacts-labels.json. On startup, Feast's load_static_artifacts() imports the deployment's static_artifacts.py, which consumes that attacker-written file and runs a configured startup hook under the Feast server process account, achieving code execution.

Which Feast versions are affected by CVE-2026-23537, and where is it fixed?

Feast (feast-dev/feast) versions before 0.60.0 are affected - the /save-document endpoint was introduced in v0.59.0 (PR #5865, commit 2081b55de32b830b4fb64e93b6d88cdfaeff2378); it is fixed in 0.60.0.

How severe is CVE-2026-23537?

Critical severity - a remote unauthenticated attacker can write arbitrary JSON files anywhere the Feast service account has filesystem write permissions.

How can I reproduce CVE-2026-23537?

Download the verified script and run it in an isolated environment against a vulnerable Feast Feature Server build; it sends an unauthenticated POST to /save-document with a path that bypasses the location check, confirms the file lands on disk, and shows the write chained through the static-artifacts startup hook into code execution.
11 · References

References for CVE-2026-23537

Authoritative sources for CVE-2026-23537 — official vulnerability databases and the upstream advisory. Pruva's reproduction verifies the issue firsthand; these are the primary records to corroborate it.