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.
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).
CVE-VINEXT-CIVETWEB-PUT-SSI-RCE Severity
CVE-VINEXT-CIVETWEB-PUT-SSI-RCE is rated high severity.
High — serious impact or readily exploitable. Prioritize remediation.
How to Reproduce CVE-VINEXT-CIVETWEB-PUT-SSI-RCE
pruva-verify REPRO-2026-00229 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 Proof of Reproduction for CVE-VINEXT-CIVETWEB-PUT-SSI-RCE
- 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
<!--#exec "id; uname -a" --> uploaded via authenticated HTTP PUT as /pwn.shtml
- 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
Root Cause and Exploit Chain for CVE-VINEXT-CIVETWEB-PUT-SSI-RCE
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 (
civetwebexecutable,src/civetweb.c). - Affected versions: The ticket names commit
588860e3. That specific commit has a build-breaking syntax error inget_request()and does not compile. The immediately preceding parent commit (588860e3^1, also known as3309a6c) is the last working master revision and still contains the vulnerabledo_ssi_exec/handle_put_filecode path. The same behavior is present in588860e3once the unrelated syntax error is corrected. - Risk level and consequences: High. Any user with a valid digest credential for the
put_delete_auth_filerealm 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
.shtmlfollowed by GET. - Reproduced impact from this run: The reproduction script authenticated with digest credentials, PUT an
.shtmlpayload containing<!--#exec "id; uname -a" -->, and a subsequent GET returned the output ofidanduname -ain 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:
- Authenticated PUT/DELETE support. When
put_delete_auth_fileis configured, CivetWeb allows any user with a valid digest credential to write arbitrary files into thedocument_root(handle_put_file()insrc/civetweb.c). - SSI
#execprocessing. The defaultssi_patternis**.shtml$|**.shtm$. When a requested file matches this pattern,send_ssi_file()scans the file for<!--#...-->tags. If the tag starts withexecandNO_POPENis not defined, it callsdo_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 thedo_ssi_execcode path and is only prevented from compiling by an unrelated syntax error inget_request().
Reproduction Steps
- Build the vulnerable server: Run
bundle/repro/reproduction_steps.sh. The script readsbundle/project_cache_context.json, clones or reuses the CivetWeb repository from the project cache, resolves the ticket-named commit588860e3, and uses its working parent588860e3^1(3309a6c) because the named commit does not compile. It builds two binaries: one default (vulnerable) and one with-DNO_POPEN(control). - Start the server: The script creates a digest password file (
admin:mydomain.com:<md5>) and starts CivetWeb withlistening_ports,document_root,put_delete_auth_file, andauthentication_domain. - Upload the payload: The script performs an authenticated HTTP PUT to
/pwn.shtmlwith the body<!--#exec "id; uname -a" -->. - 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_POPENbuild, the response body is empty because the#execdirective is not implemented. - Expected evidence:
bundle/artifacts/vulnerable-attempt1/get_body.txtcontainsuid=...andLinux ....bundle/artifacts/fixed-attempt1/get_body.txtdoes not contain either string.bundle/logs/reproduction_steps.logshows 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.txtshowsHTTP/1.1 200 OKandContent-Type: text/html. - Fixed GET response body:
bundle/artifacts/fixed-attempt1/get_body.txtis empty, confirming the#execpath is disabled whenNO_POPENis defined. - HTTP headers:
bundle/artifacts/vulnerable-attempt1/put_headers.txtandget_headers.txtshowHTTP/1.1 200 OKfor both PUT and GET. - Server logs:
bundle/artifacts/vulnerable-attempt1/server.logandbundle/artifacts/fixed-attempt1/server.logshow 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_POPENto disable SSI#execentirely, or disable PUT/DELETE by not settingput_delete_auth_file. Alternatively, restrictssi_patternso that untrusted upload directories cannot match it. - Proper fix: Remove or gate the SSI
#execdirective behind an explicit opt-in option (e.g.,ssi_exec_enabled yes) that defaults tono. When enabled, restrict it to a dedicated, non-upload directory and/or require additional authorization. Alternatively, do not allow files uploaded via PUT to matchssi_patternunless explicitly whitelisted. - Upgrade guidance: There is no known upstream fixed version at the time of this report. Users should apply the
-DNO_POPENbuild flag or disable PUT/DELETE until a patched release is available. - Testing recommendations: Add an integration test that uploads an
.shtmlfile with#execand 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
588860e3as the vulnerable version. That commit has a build-breaking syntax error insrc/civetweb.c(get_request():if (h_chunk != NULL) && ...instead ofif ((h_chunk != NULL) && ...)plus an undeclaredclvariable). The reproduction therefore uses the immediately preceding working commit588860e3^1(3309a6c), which is the parent of588860e3and 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
#execmechanism 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.
git --version && which curl && which jq && which make && which gcc && which cmake && which opensslgit version 2.55.0 /usr/bin/curl /usr/bin/jq /usr/bin/make /usr/bin/gcc /usr/bin/cmake /usr/bin/openssl
Artifacts and Evidence for CVE-VINEXT-CIVETWEB-PUT-SSI-RCE
Scripts, logs, diffs, and output captured during the reproduction.
How to Fix CVE-VINEXT-CIVETWEB-PUT-SSI-RCE
FAQ: CVE-VINEXT-CIVETWEB-PUT-SSI-RCE
What configuration makes CivetWeb exploitable here?
How severe is the CivetWeb PUT + SSI #exec issue?
How can I reproduce it?
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.