Skip to content

CVE-2026-71284: Verified Reproduction

CVE-2026-71284: Fledge backup upload shell command injection

CVE-2026-71284 is verified against fledge-iot/fledge · github. Affected versions: CVE.org lists versions 0 through 3.1.0 as affected; the ticket requires proof on 3.1.0. Vulnerability class: Command Injection. This high reproduction includes runnable sandbox proof, artifacts, and a plain-text agent view under REPRO-2026-00332.

REPRO-2026-00332 fledge-iot/fledge · github Command Injection Aug 23, 2026 CVE entry .txt
Severity
HIGH
Confidence
HIGH
Reproduced in
91m 3s
Tool calls
502
Spend
$75.20
01 · Overview

What Is CVE-2026-71284?

CVE-2026-71284 is a high-severity Command Injection vulnerability affecting fledge-iot/fledge CVE.org lists versions 0 through 3.1.0 as affected; the ticket requires proof on 3.1.0.. Pruva has independently reproduced it and publishes a verified, runnable proof-of-concept (reproduction REPRO-2026-00332).

02 · Severity & CVSS

CVE-2026-71284 Severity

CVE-2026-71284 is rated high severity.

HIGH threat level

High — serious impact or readily exploitable. Prioritize remediation.

03 · Affected Versions

Affected fledge-iot/fledge Versions

fledge-iot/fledge · github versions CVE.org lists versions 0 through 3.1.0 as affected; the ticket requires proof on 3.1.0. are affected.

How to Reproduce CVE-2026-71284

$ pruva-verify REPRO-2026-00332
or curl -O https://www.pruva.dev/api/v1/reproductions/REPRO-2026-00332/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-71284

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

The first member filename in an authenticated administrator-uploaded tar.gz backup archive

Attack chain
  1. POST /fledge/backup/upload
  2. upload_backup()
  3. tar extraction
  4. os.system('cp ' + attacker-controlled source + ' ' + backup_path)
Runnable proof: reproduction_steps.sh
Captured evidence: vulnerable 1 container consolevulnerable 1 servicevulnerable 1 shell lineagevulnerable 1 strace attachvulnerable 2 container consolevulnerable 2 servicevulnerable 2 shell lineagevulnerable 2 strace attach
How the agent worked 957 events · 502 tool calls · 1h 31m
1h 31mDuration
502Tool calls
143Reasoning steps
957Events
29Dead-ends
Agent activity over 1h 31m
Policy
1
Support
36
Repro
639
Judge
73
Variant
203
Verify
1
0:0090:51

Root Cause and Exploit Chain for CVE-2026-71284

Versions: release tested: Fledge 3.1.0, tag and commit f90ffc2047ee49a380ada98a59fcc2985bd6a943 (database schema 75). The ticket reports versions through 3.1.0 as affected.

Fledge 3.1.0 is vulnerable to authenticated OS command injection in the production backup-upload REST handler. An administrator can upload a syntactically valid .tar.gz archive whose first member starts with fledge_backup_, ends with .db, and contains shell metacharacters between those accepted strings. upload_backup() extracts that member, concatenates its path into cp {source} {backup_path}, and executes the result with os.system(). A real Fledge service consequently runs the embedded shell command as its fledge service user.

  • Product/component: fledge-iot/fledge, specifically python/fledge/services/core/api/backup_restore.py::upload_backup() and POST /fledge/backup/upload.
  • Affected release tested: Fledge 3.1.0, tag and commit f90ffc2047ee49a380ada98a59fcc2985bd6a943 (database schema 75). The ticket reports versions through 3.1.0 as affected.
  • Required attacker position: An authenticated Fledge administrator with access to the backup-upload endpoint.
  • Risk: High. The administrator can execute arbitrary local shell commands with the identity and filesystem access of the Fledge service account. In the reproduced deployment that identity was UID 10001, user/group fledge.
  • Consequence demonstrated: Deterministic command execution through the network API, including attacker-selected file creation and content.

Impact Parity

  • Disclosed/claimed maximum impact: Authenticated remote OS command execution as the Fledge service user.
  • Reproduced impact: Two fresh vulnerable Fledge 3.1.0 service instances accepted authenticated crafted uploads. Each spawned /bin/sh -c with the attacker-controlled member filename and created a distinct attacker-selected marker as fledge.
  • Parity: full.
  • Not demonstrated: No privilege escalation beyond the Fledge service account, lateral movement, persistence, or outbound network behavior was attempted or required. These are not part of the claimed maximum impact.

Root Cause

The handler applies validation to two different filename layers:

  1. The outer multipart filename must start with fledge_backup_ and end in .tar.gz.
  2. At least one archive member must start with fledge_backup_ and end in .db or .dump.

For archives compatible with older Fledge versions, the handler calls tar_file.extractall(temp_path), assigns backup_file_name = tar_file_names[0], and builds source = temp_path + "/" + backup_file_name. The prefix/suffix checks do not reject shell syntax inside the accepted member name. The vulnerable code then performs:

cmd = "cp {} {}".format(source, backup_path)
ret_code = os.system(cmd)

os.system() invokes a command shell. Consequently, characters such as ;, redirections, and # in source become shell syntax instead of literal filename bytes. The proof member retains the accepted prefix and .db suffix while placing ;printf ...;sleep 2;# between them. The generated shell command runs printf, and the comment suppresses the remainder of the cp command.

No upstream fixed release or fix commit was identified in the ticket or the tested repository state. The reproduction therefore labels its negative control as a same-version patched control, not as an upstream fixed version. That control changes only the unsafe copy block to shutil.copy2(source, backup_path). It accepts the same request and copies the literal filename without interpreting its metacharacters, proving that the shell sink is causal.

Reproduction Steps

  1. Run bundle/repro/reproduction_steps.sh from any directory. The script resolves PRUVA_ROOT, uses /pruva/project-cache/repo when the prepared cache contract permits it, and otherwise falls back to bundle/artifacts/fledge.
  2. The script checks out exact commit f90ffc2047ee49a380ada98a59fcc2985bd6a943, verifies the vulnerable source statements, and builds the real Fledge product in a pinned Ubuntu 22.04 base image. Compilation is bounded to two jobs. The runtime includes the normal rsyslog socket and starts Fledge through its shipped bin/fledge start flow.
  3. It generates deterministic minimal archives at runtime and exercises:
    • one normal valid backup upload (marker must remain absent);
    • two fresh vulnerable service instances with distinct crafted archives and markers;
    • two fresh same-version patched-control instances with the exact corresponding archive bytes (requests succeed, literal files are copied, and markers remain absent).
  4. Each service must become healthy at /fledge/ping, report version 3.1.0 with mandatory authentication, and accept a normal admin login before the upload.
  5. The vulnerable requests must return HTTP 200, produce service debug logs showing the generated cp command, produce strace evidence of /bin/sh -c, show the shell as a child of the Fledge core process, and create markers owned by fledge.
  6. Expected final output includes:
[+] CONFIRMED: authenticated remote OS command execution through Fledge 3.1.0 backup upload API
[+] Vulnerable markers: PRUVA_CVE_2026_71284_ATTEMPT_1, PRUVA_CVE_2026_71284_ATTEMPT_2
[+] Benign and same-version patched controls reached the endpoint without marker execution

The final script was executed twice consecutively and returned exit status 0 on both runs.

Evidence

Current-run evidence is under bundle/logs/repro/cve-2026-71284/; bundle/repro/runtime_manifest.json binds every finalized artifact to its SHA-256.

Key artifacts include:

  • proof_summary.json — concise result, exact commit and image identities, four fresh process/container identities, two successful vulnerable markers, and negative-control outcomes.
  • source_identity.json — repository, v3.1.0 commit, vulnerable file digest, and canonical source target digest.
  • runtime_image_identity.txt — pinned base, vulnerable image ID, patched-control image ID, and Docker inspection output.
  • vulnerable_1_health_response.json and vulnerable_2_health_response.json — real service health, version 3.1.0, and mandatory authentication.
  • vulnerable_{1,2}_login_request.json / login_response.json — normal administrator authentication with current tokens redacted from retained proof.
  • vulnerable_{1,2}_upload_request.json / upload_response.json — authenticated production endpoint transactions.
  • vulnerable_{1,2}_service.log — handler debug output containing attacker-controlled source and the constructed shell command.
  • vulnerable_{1,2}_execve_trace.log and shell_lineage.log — syscall/process evidence. A representative excerpt is:
execve("/bin/sh", ["sh", "-c", "cp /var/lib/fledge/upload/fledge_backup_...db;printf PRUVA_CVE_2026_71284_ATTEMPT_1 >/tmp/pruva_cve_2026_71284_attempt_1;sleep 2;#.db /var/lib/fledge/backup"], ...)
  • vulnerable_1_process_tree_during_attack.txt — live lineage showing PID 155 python3 -m fledge.services.core (user fledge) parenting PID 579 sh -c ..., which parents sleep 2.
  • vulnerable_{1,2}_marker.txt — exact attacker-selected marker bytes.
  • vulnerable_{1,2}_marker_stat.txt — marker ownership and mode. Both record uid=10001 user=fledge ... group=fledge.
  • benign_control_* — a conventional valid backup succeeds without a marker and appears in the backup directory.
  • patched_{1,2}_negative_control.json, patched_{1,2}_execve_trace.log, patched_{1,2}_service.log, and patched_{1,2}_backup_listing.txt — the same crafted archive reaches the same endpoint in the same release, but no attacker command is passed to execve; the source is copied as a literal filename and no marker appears.
  • patched_control_source.txt — exact behavior-preserving control statement using shutil.copy2.
  • bundle/logs/reproduction_steps.log and bundle/logs/fledge-image-build.log — diagnostics for the final run; these are not hashed as immutable proof while active.

The final runtime manifest records entrypoint_kind="endpoint", service_started=true, healthcheck_passed=true, target_path_reached=true, exact source commit, source target digest, vulnerable runtime image digest, Linux/x86-64 platform, and 101 finalized proof artifacts.

Recommendations / Next Steps

  1. Remove the shell from the copy operation. Prefer shutil.copy2(source, backup_path) or another API that treats source and destination as literal path arguments. If an external utility is unavoidable, invoke it with an argument vector and shell=False; do not build a shell command string.
  2. Validate and normalize every archive member before extraction. Reject absolute paths, .. traversal, links, device entries, control characters, and filenames outside a narrowly defined grammar. Extract only explicitly accepted members rather than calling unrestricted extractall().
  3. Do not rely solely on startswith()/endswith() for a security boundary. A suitable allowlist should constrain the entire backup basename, for example a known timestamp pattern and the exact .db/.dump extension.
  4. Add production-path tests that upload names containing ;, $(), backticks, quotes, whitespace, redirection operators, glob characters, newlines, and traversal sequences. Assert no child shell is created and that literal-safe backups still work.
  5. Add a regression test using the same crafted archive against the real authenticated API and monitor process ancestry (Fledge core -> shell) to ensure the unsafe behavior is gone.
  6. Until an upstream release containing a verified fix exists, restrict the endpoint to trusted administrators, isolate the service account, minimize writable paths and privileges, and alert on shell processes spawned by the Fledge core service.

Additional Notes

  • Idempotency: Confirmed. The script removes prior evidence/work directories and uniquely names containers; it completed successfully twice in succession. Each individual final run itself used two clean vulnerable and two clean patched-control service instances.
  • Real boundary: The proof uses the compiled Fledge 3.1.0 core and storage service, normal product initialization, /fledge/login, and POST /fledge/backup/upload over localhost TCP. It does not invoke upload_backup() directly and uses no mock handler.
  • Sanitizers: None used. The success oracle is real command execution, not a sanitizer or crash.
  • Authentication: Fledge's normal first-install administrator credential was used only inside the isolated containers. Retained request evidence redacts the credential and retained responses redact JWTs.
  • Container capabilities: SYS_PTRACE and an unconfined seccomp profile are used only so strace can capture child process execution. They do not enable the injection, change product parsing, or create the marker; vulnerable execution was independently observed before adding tracing.
  • Upstream status: No released fixed version is asserted. The negative control is explicitly source-modified Fledge 3.1.0 for causal verification.
  • Limitations: The proof requires a working Docker daemon and network access on an uncached first build to obtain the pinned base and package dependencies. It performs no outbound access from the exploit payload.

CVE-2026-71284 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:004:27
0:00
session startedgpt-5.6-sol · CVE-2026-71284 · REPRO-20
0:06
0:08
web search
0:23
0:24
web search
0:26
web search
0:27
web search
0:30
0:47
0:47
0:48
0:49
0:51
web search
0:52
web search
1:24
1:24
1:24
1:24
1:24
1:26
web search
2:49
2:51
2:53
2:53
2:59
web search
4:14
4:14
4:14
4:14
extract_facts
no facts extracted
4:18
4:18
supportclaim_contract

Artifacts and Evidence for CVE-2026-71284

Scripts, logs, diffs, and output captured during the reproduction.

bundle/logs/repro/cve-2026-71284/benign_control_backup_listing.txt0.0 KB
bundle/logs/repro/cve-2026-71284/benign_control_observation.json0.2 KB
bundle/logs/repro/cve-2026-71284/benign_control_upload_request.json0.3 KB
bundle/logs/repro/cve-2026-71284/benign_control_upload_response.headers0.2 KB
bundle/logs/repro/cve-2026-71284/benign_control_upload_response.json0.1 KB
bundle/logs/repro/cve-2026-71284/inputs/archive_sha256.txt0.4 KB
bundle/logs/repro/cve-2026-71284/inputs/attack_1_member_name.txt0.1 KB
bundle/logs/repro/cve-2026-71284/inputs/attack_2_member_name.txt0.1 KB
bundle/logs/repro/cve-2026-71284/inputs/fledge_backup_attack_1.tar.gz0.3 KB
bundle/logs/repro/cve-2026-71284/inputs/fledge_backup_attack_2.tar.gz0.3 KB
bundle/logs/repro/cve-2026-71284/inputs/fledge_backup_benign.tar.gz0.2 KB
bundle/logs/repro/cve-2026-71284/patched_1_backup_listing.txt0.0 KB
bundle/logs/repro/cve-2026-71284/patched_1_container_console.log29.7 KB
bundle/logs/repro/cve-2026-71284/patched_1_container_final.json9.7 KB
bundle/logs/repro/cve-2026-71284/patched_1_container_running.json10.1 KB
bundle/logs/repro/cve-2026-71284/patched_1_execve_trace.log2.5 KB
bundle/logs/repro/cve-2026-71284/patched_1_final_process_tree.txt0.7 KB
bundle/logs/repro/cve-2026-71284/patched_1_health_request.txt0.0 KB
bundle/logs/repro/cve-2026-71284/patched_1_health_response.json0.2 KB
bundle/logs/repro/cve-2026-71284/patched_1_logging_request.json0.1 KB
bundle/logs/repro/cve-2026-71284/patched_1_logging_response.json0.2 KB
bundle/logs/repro/cve-2026-71284/patched_1_login_request.json0.2 KB
bundle/logs/repro/cve-2026-71284/patched_1_login_response.headers0.2 KB
bundle/logs/repro/cve-2026-71284/patched_1_login_response.json0.1 KB
bundle/logs/repro/cve-2026-71284/patched_1_negative_control.json0.2 KB
bundle/logs/repro/cve-2026-71284/patched_1_runtime_identity.txt29.8 KB
bundle/logs/repro/cve-2026-71284/patched_1_service.log17.3 KB
bundle/logs/repro/cve-2026-71284/patched_1_strace_attach.log0.4 KB
bundle/logs/repro/cve-2026-71284/patched_1_upload_request.json0.3 KB
bundle/logs/repro/cve-2026-71284/patched_1_upload_response.headers0.2 KB
bundle/logs/repro/cve-2026-71284/patched_1_upload_response.json0.1 KB
bundle/logs/repro/cve-2026-71284/patched_2_backup_listing.txt0.0 KB
bundle/logs/repro/cve-2026-71284/patched_2_container_console.log30.2 KB
bundle/logs/repro/cve-2026-71284/patched_2_container_final.json9.7 KB
bundle/logs/repro/cve-2026-71284/patched_2_container_running.json10.1 KB
bundle/logs/repro/cve-2026-71284/patched_2_execve_trace.log2.6 KB
bundle/logs/repro/cve-2026-71284/patched_2_final_process_tree.txt0.7 KB
bundle/logs/repro/cve-2026-71284/patched_2_health_request.txt0.0 KB
bundle/logs/repro/cve-2026-71284/patched_2_health_response.json0.2 KB
bundle/logs/repro/cve-2026-71284/patched_2_logging_request.json0.1 KB
bundle/logs/repro/cve-2026-71284/patched_2_logging_response.json0.2 KB
bundle/logs/repro/cve-2026-71284/patched_2_login_request.json0.2 KB
bundle/logs/repro/cve-2026-71284/patched_2_login_response.headers0.2 KB
bundle/logs/repro/cve-2026-71284/patched_2_login_response.json0.1 KB
bundle/logs/repro/cve-2026-71284/patched_2_negative_control.json0.2 KB
bundle/logs/repro/cve-2026-71284/patched_2_runtime_identity.txt30.2 KB
bundle/logs/repro/cve-2026-71284/patched_2_service.log17.3 KB
bundle/logs/repro/cve-2026-71284/patched_2_strace_attach.log0.5 KB
bundle/logs/repro/cve-2026-71284/patched_2_upload_request.json0.3 KB
bundle/logs/repro/cve-2026-71284/patched_2_upload_response.headers0.2 KB
bundle/logs/repro/cve-2026-71284/patched_2_upload_response.json0.1 KB
bundle/logs/repro/cve-2026-71284/patched_control_source.txt0.5 KB
bundle/logs/repro/cve-2026-71284/proof_summary.json1.2 KB
bundle/logs/repro/cve-2026-71284/runtime_image_identity.txt9.0 KB
bundle/logs/repro/cve-2026-71284/source_identity.json0.3 KB
bundle/logs/repro/cve-2026-71284/vulnerable_1_capability_observation.json0.2 KB
bundle/logs/repro/cve-2026-71284/vulnerable_1_container_console.log5.9 KB
bundle/logs/repro/cve-2026-71284/vulnerable_1_container_final.json9.4 KB
bundle/logs/repro/cve-2026-71284/vulnerable_1_container_running.json9.9 KB
bundle/logs/repro/cve-2026-71284/vulnerable_1_final_process_tree.txt0.6 KB
bundle/logs/repro/cve-2026-71284/vulnerable_1_health_request.txt0.0 KB
bundle/logs/repro/cve-2026-71284/vulnerable_1_health_response.json0.2 KB
bundle/logs/repro/cve-2026-71284/vulnerable_1_logging_request.json0.1 KB
bundle/logs/repro/cve-2026-71284/vulnerable_1_logging_response.json0.2 KB
bundle/logs/repro/cve-2026-71284/vulnerable_1_login_request.json0.2 KB
bundle/logs/repro/cve-2026-71284/vulnerable_1_login_response.headers0.2 KB
bundle/logs/repro/cve-2026-71284/vulnerable_1_login_response.json0.1 KB
bundle/logs/repro/cve-2026-71284/vulnerable_1_marker.txt0.0 KB
bundle/logs/repro/cve-2026-71284/vulnerable_1_marker_stat.txt0.1 KB
bundle/logs/repro/cve-2026-71284/vulnerable_1_runtime_identity.txt29.9 KB
bundle/logs/repro/cve-2026-71284/vulnerable_1_service.log18.2 KB
bundle/logs/repro/cve-2026-71284/vulnerable_1_shell_lineage.log0.3 KB
bundle/logs/repro/cve-2026-71284/vulnerable_1_strace_attach.log0.6 KB
bundle/logs/repro/cve-2026-71284/vulnerable_1_upload_response.headers0.2 KB
bundle/logs/repro/cve-2026-71284/vulnerable_1_upload_response.json0.1 KB
bundle/logs/repro/cve-2026-71284/vulnerable_2_capability_observation.json0.2 KB
bundle/logs/repro/cve-2026-71284/vulnerable_2_container_console.log31.2 KB
bundle/logs/repro/cve-2026-71284/vulnerable_2_container_final.json9.4 KB
bundle/logs/repro/cve-2026-71284/vulnerable_2_container_running.json9.9 KB
bundle/logs/repro/cve-2026-71284/vulnerable_2_final_process_tree.txt0.7 KB
bundle/logs/repro/cve-2026-71284/vulnerable_2_health_request.txt0.0 KB
bundle/logs/repro/cve-2026-71284/vulnerable_2_health_response.json0.2 KB
bundle/logs/repro/cve-2026-71284/vulnerable_2_logging_request.json0.1 KB
bundle/logs/repro/cve-2026-71284/vulnerable_2_logging_response.json0.2 KB
bundle/logs/repro/cve-2026-71284/vulnerable_2_login_request.json0.2 KB
bundle/logs/repro/cve-2026-71284/vulnerable_2_login_response.headers0.2 KB
bundle/logs/repro/cve-2026-71284/vulnerable_2_login_response.json0.1 KB
bundle/logs/repro/cve-2026-71284/vulnerable_2_marker.txt0.0 KB
bundle/logs/repro/cve-2026-71284/vulnerable_2_marker_stat.txt0.1 KB
bundle/logs/repro/cve-2026-71284/vulnerable_2_process_tree_during_attack.txt2.3 KB
bundle/logs/repro/cve-2026-71284/vulnerable_2_runtime_identity.txt30.1 KB
bundle/logs/repro/cve-2026-71284/vulnerable_2_service.log18.4 KB
bundle/logs/repro/cve-2026-71284/vulnerable_2_shell_lineage.log0.3 KB
bundle/logs/repro/cve-2026-71284/vulnerable_2_strace_attach.log0.6 KB
bundle/logs/repro/cve-2026-71284/vulnerable_2_upload_request.json0.3 KB
bundle/logs/repro/cve-2026-71284/vulnerable_2_upload_response.headers0.2 KB
bundle/logs/repro/cve-2026-71284/vulnerable_2_upload_response.json0.1 KB
bundle/repro/rca_report.md11.0 KB
bundle/repro/reproduction_steps.sh29.4 KB
bundle/repro/runtime_manifest.json20.4 KB
bundle/repro/validation_verdict.json0.8 KB
08 · How to Fix

How to Fix CVE-2026-71284

Coming soon

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

10 · FAQ

FAQ: CVE-2026-71284

Is CVE-2026-71284 exploitable?

Yes. Pruva independently reproduced CVE-2026-71284 in fledge-iot/fledge and verified the exploit fires end-to-end in a sandboxed environment. A runnable proof-of-concept script and the full agent transcript are on this page (reproduction REPRO-2026-00332).

How severe is CVE-2026-71284?

CVE-2026-71284 is rated high severity.

Which versions of fledge-iot/fledge are affected by CVE-2026-71284?

fledge-iot/fledge CVE.org lists versions 0 through 3.1.0 as affected; the ticket requires proof on 3.1.0. is affected by CVE-2026-71284.

How can I reproduce CVE-2026-71284?

Pruva provides a verified reproduction script on this page. Download it and run it inside an isolated environment such as a container or virtual machine — never against production. The reproduction was confirmed end-to-end by Pruva's automated agents.

Is the CVE-2026-71284 reproduction verified?

Yes. Pruva reproduced CVE-2026-71284 with high confidence in a sandboxed environment, capturing the full agent transcript and artifacts as evidence.
11 · References

References for CVE-2026-71284

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