Skip to content

CVE-VINEXT-CIVETWEB-PUT-SSI-RCE: Verified Reproduction

CVE-VINEXT-CIVETWEB-PUT-SSI-RCE: CivetWeb PUT + SSI exec RCE

CVE-VINEXT-CIVETWEB-PUT-SSI-RCE is verified against civetweb/civetweb · github. Vulnerability class: RCE. This high reproduction includes runnable sandbox proof, artifacts, and a plain-text agent view under REPRO-2026-00229.

REPRO-2026-00229 civetweb/civetweb · github RCE Jul 4, 2026 CVE entry .txt
Severity
HIGH
Confidence
HIGH
Reproduced in
34m 27s
Tool calls
374
Spend
$3.17
01 · Overview

What Is CVE-VINEXT-CIVETWEB-PUT-SSI-RCE?

It is a high-severity authenticated remote code execution in CivetWeb that combines its HTTP PUT upload feature with Server-Side Include (SSI) #exec processing. An authenticated user can upload a .shtml file that runs a shell command when fetched. Pruva reproduced it (reproduction REPRO-2026-00229).

02 · Severity & CVSS

CVE-VINEXT-CIVETWEB-PUT-SSI-RCE Severity

CVE-VINEXT-CIVETWEB-PUT-SSI-RCE is rated high severity.

HIGH threat level

High — serious impact or readily exploitable. Prioritize remediation.

How to Reproduce CVE-VINEXT-CIVETWEB-PUT-SSI-RCE

$ pruva-verify REPRO-2026-00229
or curl -O https://www.pruva.dev/api/v1/reproductions/REPRO-2026-00229/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-VINEXT-CIVETWEB-PUT-SSI-RCE

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

<!--#exec "id; uname -a" --> uploaded via authenticated HTTP PUT as /pwn.shtml

Attack chain
  1. HTTP PUT /pwn.shtml followed by HTTP GET /pwn.shtml on a CivetWeb instance with put_delete_auth_file and default ssi_pattern
How the agent worked 893 events · 374 tool calls · 34 min
34 minDuration
374Tool calls
254Reasoning steps
893Events
1Dead-ends
Agent activity over 34 min
Support
39
Hypothesis
4
Repro
221
Judge
52
Variant
325
Coding
243
0:0034:27

Root Cause and Exploit Chain for CVE-VINEXT-CIVETWEB-PUT-SSI-RCE

Versions: The ticket names commit 588860e3. That specific commit has a build-breaking syntax error in get_request() and does not compile. The immediately preceding parent commit (588860e3^1, also known as 3309a6c) is the last working master revision and still contains the vulnerable do_ssi_exec / handle_put_file code path. The same behavior is present in 588860e3 once the unrelated syntax error is corrected.

CivetWeb’s default ssi_pattern causes files ending in .shtml or .shtm to be processed as Server Side Includes (SSI). When the put_delete_auth_file option is enabled, CivetWeb accepts authenticated HTTP PUT uploads. Because files uploaded via PUT live in the configured document_root, a subsequent GET request for a .shtml upload is handled by the SSI engine. The SSI parser calls do_ssi_exec() on <!--#exec "..."--> tags, which passes the command string directly to popen(). An authenticated attacker can therefore upload a .shtml file containing an SSI #exec directive and execute arbitrary shell commands on the server by requesting that file.

  • Package/component affected: CivetWeb HTTP server (civetweb executable, src/civetweb.c).
  • Affected versions: The ticket names commit 588860e3. That specific commit has a build-breaking syntax error in get_request() and does not compile. The immediately preceding parent commit (588860e3^1, also known as 3309a6c) is the last working master revision and still contains the vulnerable do_ssi_exec / handle_put_file code path. The same behavior is present in 588860e3 once the unrelated syntax error is corrected.
  • Risk level and consequences: High. Any user with a valid digest credential for the put_delete_auth_file realm can upload and execute arbitrary shell commands as the CivetWeb process user, leading to full host compromise.

Impact Parity

  • Disclosed/claimed maximum impact: Authenticated remote code execution via PUT upload of .shtml followed by GET.
  • Reproduced impact from this run: The reproduction script authenticated with digest credentials, PUT an .shtml payload containing <!--#exec "id; uname -a" -->, and a subsequent GET returned the output of id and uname -a in the HTTP response body. This proves the server executed attacker-controlled shell commands through the real HTTP API.
  • Parity: full
  • Not demonstrated: N/A — the claimed code-execution path was demonstrated end-to-end through the real HTTP API.

Root Cause

The root cause is the interaction of two default/documented features without sufficient isolation:

  1. Authenticated PUT/DELETE support. When put_delete_auth_file is configured, CivetWeb allows any user with a valid digest credential to write arbitrary files into the document_root (handle_put_file() in src/civetweb.c).
  2. SSI #exec processing. The default ssi_pattern is **.shtml$|**.shtm$. When a requested file matches this pattern, send_ssi_file() scans the file for <!--#...--> tags. If the tag starts with exec and NO_POPEN is not defined, it calls do_ssi_exec(conn, buf + 9):
#if !defined(NO_POPEN)
static void
do_ssi_exec(struct mg_connection *conn, char *tag)
{
    char cmd[1024] = "";
    struct mg_file file = STRUCT_FILE_INITIALIZER;

    if (sscanf(tag, " \"%1023[^\"]\"", cmd) != 1) {
        mg_cry_internal(conn, "Bad SSI #exec: [%s]", tag);
    } else {
        cmd[1023] = 0;
        if ((file.access.fp = popen(cmd, "r")) == NULL) {
            mg_cry_internal(conn,
                            "Cannot SSI #exec: [%s]: %s",
                            cmd,
                            strerror(ERRNO));
        } else {
            send_file_data(conn, &file, 0, INT64_MAX, 0); /* send static file */
            pclose(file.access.fp);
        }
    }
}
#endif /* !NO_POPEN */

The command string is extracted from the SSI tag and passed unmodified to popen(), which runs it with the privileges of the CivetWeb process. There is no additional authorization check for #exec beyond the SSI file pattern match, and no restriction on which files created via PUT may be treated as SSI.

  • Link to fix commit: No upstream fix commit was identified in the repository at the time of this run. The current master (588860e3) still contains the do_ssi_exec code path and is only prevented from compiling by an unrelated syntax error in get_request().

Reproduction Steps

  1. Build the vulnerable server: Run bundle/repro/reproduction_steps.sh. The script reads bundle/project_cache_context.json, clones or reuses the CivetWeb repository from the project cache, resolves the ticket-named commit 588860e3, and uses its working parent 588860e3^1 (3309a6c) because the named commit does not compile. It builds two binaries: one default (vulnerable) and one with -DNO_POPEN (control).
  2. Start the server: The script creates a digest password file (admin:mydomain.com:<md5>) and starts CivetWeb with listening_ports, document_root, put_delete_auth_file, and authentication_domain.
  3. Upload the payload: The script performs an authenticated HTTP PUT to /pwn.shtml with the body <!--#exec "id; uname -a" -->.
  4. Trigger execution: The script sends an authenticated HTTP GET to /pwn.shtml. On the vulnerable build, the response body contains the output of the executed commands. On the -DNO_POPEN build, the response body is empty because the #exec directive is not implemented.
  5. Expected evidence:
    • bundle/artifacts/vulnerable-attempt1/get_body.txt contains uid=... and Linux ....
    • bundle/artifacts/fixed-attempt1/get_body.txt does not contain either string.
    • bundle/logs/reproduction_steps.log shows two vulnerable attempts returning command output and two fixed attempts returning no command output.

Evidence

  • Log file: bundle/logs/reproduction_steps.log
  • Vulnerable GET response body: bundle/artifacts/vulnerable-attempt1/get_body.txt:
    uid=1000(vscode) gid=1000(vscode) groups=1000(vscode),962(962)
    Linux d778bdddc001 7.0.14-arch1-1 #1 SMP PREEMPT_DYNAMIC Sat, 27 Jun 2026 16:15:10 +0000 x86_64 GNU/Linux
    
  • Vulnerable GET response headers: bundle/artifacts/vulnerable-attempt1/get_headers.txt shows HTTP/1.1 200 OK and Content-Type: text/html.
  • Fixed GET response body: bundle/artifacts/fixed-attempt1/get_body.txt is empty, confirming the #exec path is disabled when NO_POPEN is defined.
  • HTTP headers: bundle/artifacts/vulnerable-attempt1/put_headers.txt and get_headers.txt show HTTP/1.1 200 OK for both PUT and GET.
  • Server logs: bundle/artifacts/vulnerable-attempt1/server.log and bundle/artifacts/fixed-attempt1/server.log show the CivetWeb startup and shutdown.
  • Environment: Reproduced on Linux x86_64 with gcc, using CivetWeb built from source at commit 3309a6c (588860e3^1).

Recommendations / Next Steps

  • Short-term mitigation: Build CivetWeb with -DNO_POPEN to disable SSI #exec entirely, or disable PUT/DELETE by not setting put_delete_auth_file. Alternatively, restrict ssi_pattern so that untrusted upload directories cannot match it.
  • Proper fix: Remove or gate the SSI #exec directive behind an explicit opt-in option (e.g., ssi_exec_enabled yes) that defaults to no. When enabled, restrict it to a dedicated, non-upload directory and/or require additional authorization. Alternatively, do not allow files uploaded via PUT to match ssi_pattern unless explicitly whitelisted.
  • Upgrade guidance: There is no known upstream fixed version at the time of this report. Users should apply the -DNO_POPEN build flag or disable PUT/DELETE until a patched release is available.
  • Testing recommendations: Add an integration test that uploads an .shtml file with #exec and verifies that no command is executed, and that the response body does not contain shell command output.

Additional Notes

  • Idempotency: The reproduction script was run twice consecutively from the same project-cache state and produced identical confirmation results in both runs.
  • Commit discrepancy: The ticket names commit 588860e3 as the vulnerable version. That commit has a build-breaking syntax error in src/civetweb.c (get_request(): if (h_chunk != NULL) && ... instead of if ((h_chunk != NULL) && ...) plus an undeclared cl variable). The reproduction therefore uses the immediately preceding working commit 588860e3^1 (3309a6c), which is the parent of 588860e3 and contains the same vulnerable SSI code path.
  • Limitations: The reproduction demonstrates authenticated RCE against a locally running CivetWeb instance. Actual deployments may differ in user privilege, authentication domain, or file-system layout, but the underlying SSI #exec mechanism is the same.

CVE-VINEXT-CIVETWEB-PUT-SSI-RCE 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:44
0:00
session startedaccounts/fireworks/models/kimi-k2p7-code · CVE-VINEXT-CIVETWEB · REPRO-20
0:05
0:07
web search
0:08
0:10
web search
0:12
0:14
0:17
0:18
web search
0:38
0:38
extract_facts
no facts extracted
0:39
0:39
0:39
supportrepro
1:20
1:22
1:22
1:22
1:24
1:24
1:24
1:31
1:32
1:37
1:37
1:39
1:39
$git --version && which curl && which jq && which make && which gcc && which cmake && which openssl
git version 2.55.0
/usr/bin/curl
/usr/bin/jq
/usr/bin/make
/usr/bin/gcc
/usr/bin/cmake
/usr/bin/openssl
1:44
08 · How to Fix

How to Fix CVE-VINEXT-CIVETWEB-PUT-SSI-RCE

Coming soon

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

10 · FAQ

FAQ: CVE-VINEXT-CIVETWEB-PUT-SSI-RCE

What configuration makes CivetWeb exploitable here?

The server must have put_delete_auth_file enabled (Digest authentication for PUT/DELETE) so authenticated PUT uploads are accepted, and the default SSI handling for .shtml files must be active — so an uploaded .shtml with an #exec directive is executed on retrieval.

How severe is the CivetWeb PUT + SSI #exec issue?

It is rated high severity: any authenticated user permitted to PUT files can achieve command execution on the server via a crafted .shtml upload and a follow-up GET.

How can I reproduce it?

Download the verified script from this page and run it in an isolated environment against a CivetWeb instance with put_delete_auth_file enabled. It PUTs a .shtml file containing an #exec directive, then GETs it, showing the injected command run by do_ssi_exec().
11 · References

References for CVE-VINEXT-CIVETWEB-PUT-SSI-RCE

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