# REPRO-2026-00252: Divi Form Builder WordPress plugin allows unauthenticated arbitrary file upload via user-controlled acceptFileTypes, leading to RCE by uploading executable PHP extensions and accessing them in /wp-content/uploads/de_fb_uploads/. ## Summary Status: published Severity: critical Type: security Confidence: high ## Identifiers REPRO ID: REPRO-2026-00252 CVE: CVE-2026-5524 ## Package Name: divi-form-builder Ecosystem: wordpress Affected: All versions up to and including 5.1.8 Fixed: Unknown ## Root Cause ## Summary Divi Form Builder for WordPress exposes its file-upload handler through WordPress AJAX action `de_fb_image_upload`, which is registered to the PHP method `do_image_upload()` for unauthenticated callers. In the original Divi Form Builder v5.1.2 build used in this run, the handler reads the attacker-controlled POST parameter `acceptFileTypes` and interpolates it into the server-side upload validation regex. An unauthenticated attacker who obtains a public form nonce can set `acceptFileTypes=phtml|phar|php5|php7`, upload a PHP-executable file such as `.phtml` into `/wp-content/uploads/de_fb_uploads/`, and then request that file over HTTP to execute PHP code under the web-server user. ## Impact - **Package/component affected:** Divi Form Builder WordPress plugin (`wordpress:divi-form-builder`), specifically `includes/classes/init.class.php::do_image_upload()` and the upload storage handled by `includes/de_fb_file_upload.php`. - **Affected versions:** The ticket claims all versions up to and including 5.1.8. This run reproduced the issue against an original Divi Form Builder v5.1.2 plugin archive (`sha256=85bf508b12f6d6152f06f8c5eb3143963c3446a7338e90e1de180f5da8a51c34`). - **Risk level and consequences:** Critical. The vulnerable path is reachable by unauthenticated HTTP requests with a valid public form nonce. Successful exploitation allows arbitrary PHP payload upload and web request execution as the Apache/PHP user (`www-data` in this reproduction), which is remote code execution. ## Impact Parity - **Disclosed/claimed maximum impact:** Remote code execution via unauthenticated arbitrary file upload. - **Reproduced impact from this run:** Full PHP code execution through the live WordPress/Apache product path. The uploaded `.phtml` payload executed and returned `uid=33(www-data) gid=33(www-data) groups=33(www-data)` from `system('id')`. - **Parity:** `full`. - **Not demonstrated:** No post-exploitation persistence or privilege escalation beyond the web-server user was attempted; this is not needed to prove the claimed RCE impact. ## Root Cause The original plugin registers the public AJAX upload action to `do_image_upload()`: - `includes/classes/init.class.php` registers `wp_ajax_de_fb_image_upload` and `wp_ajax_nopriv_de_fb_image_upload` to `do_image_upload()`. - `do_image_upload()` reads `$_POST['acceptFileTypes']` and constructs upload validation options as `'/\.(' . $accept_file_types . ')$/i'`. - `includes/de_fb_file_upload.php` validates the uploaded filename with `preg_match($this->options['accept_file_types'], $file->name)`, then writes the file to `wp-content/uploads/de_fb_uploads/` and returns a public URL. Because the extension allow-list comes from the request, the attacker controls the server-side validation pattern. Supplying `phtml|phar|php5|php7` makes `.phtml` pass validation. In the tested Apache/PHP environment, `.phtml` is handled by PHP, so requesting `/wp-content/uploads/de_fb_uploads/payload.phtml` executes the attacker-controlled payload. The plugin’s upload-directory protection is insufficient for this class of extension bypass and is also server dependent. No upstream fixed commit was provided in the ticket. For the negative control, `reproduction_steps.sh` applies a line-accurate local hardening patch over the same original plugin tree so that `do_image_upload()` rejects executable extension values before constructing the upload handler options. The patched control returns `{"success":false,"data":{"message":"Executable file types are not allowed."}}` and the corresponding uploaded URL is absent/404. ## Reproduction Steps 1. Run `bundle/repro/reproduction_steps.sh` from the bundle root (or set `PRUVA_ROOT` to the bundle path). 2. The script installs/starts a real WordPress stack with Apache, mod_php, and MariaDB, installs the original Divi Form Builder v5.1.2 plugin archive, creates a public page containing a form nonce, and sends unauthenticated multipart POST requests to `/wp-admin/admin-ajax.php` with `action=de_fb_image_upload`, `fb_nonce`, attacker-controlled `acceptFileTypes`, and a `.phtml` payload. 3. It performs two vulnerable attempts and then swaps in a patched copy of the same original plugin tree for two fixed negative-control attempts. 4. Expected evidence: vulnerable attempts return an upload JSON object containing `/wp-content/uploads/de_fb_uploads/payload_vuln_*.phtml`; subsequent GET requests to those URLs execute PHP and return the marker plus `id` output. Fixed attempts return the JSON rejection message and the payload URL returns 404/no marker. ## Evidence - Main run log: `bundle/logs/reproduction_steps.log` - Runtime manifest: `bundle/repro/runtime_manifest.json` - Original source identity: `bundle/logs/source_identity.txt` - Vulnerable attempt artifacts: - `bundle/logs/vuln_attempt_1/upload_response.json` - `bundle/logs/vuln_attempt_1/execution_response.txt` - `bundle/logs/vuln_attempt_1/result.json` - `bundle/logs/vuln_attempt_2/upload_response.json` - `bundle/logs/vuln_attempt_2/execution_response.txt` - `bundle/logs/vuln_attempt_2/result.json` - Fixed negative-control artifacts: - `bundle/logs/fixed_attempt_1/upload_response.json` - `bundle/logs/fixed_attempt_1/execution_response.txt` - `bundle/logs/fixed_attempt_1/result.json` - `bundle/logs/fixed_attempt_2/upload_response.json` - `bundle/logs/fixed_attempt_2/execution_response.txt` - `bundle/logs/fixed_attempt_2/result.json` - Patch used for negative control: `bundle/logs/fixed_patch.diff` - HTTP server evidence: `bundle/logs/apache_access.log`, `bundle/logs/apache_error.log` Key vulnerable evidence excerpt from `bundle/logs/vuln_attempt_1/result.json`: ```json { "upload_http_code": "200", "execution_http_code": "200", "uploaded_or_accepted": true, "rce_observed": true, "execution_response_excerpt": "PRUVA_DFB_RCE_MARKER=PRUVA_CVE_2026_5524_vuln_1\nPHP_EXECUTED_AS=www-data\nCMD_OUTPUT_BEGIN\nuid=33(www-data) gid=33(www-data) groups=33(www-data)\n\nCMD_OUTPUT_END\n" } ``` Key fixed-control evidence excerpt from `bundle/logs/fixed_attempt_1/result.json`: ```json { "upload_http_code": "200", "execution_http_code": "404", "uploaded_or_accepted": false, "rce_observed": false, "upload_response_excerpt": "{\"success\":false,\"data\":{\"message\":\"Executable file types are not allowed.\"}}", "server_marker": "(no marker)" } ``` The runtime manifest confirms the API surface was exercised: ```json { "entrypoint_kind": "api_remote", "service_started": true, "healthcheck_passed": true, "target_path_reached": true } ``` ## Recommendations / Next Steps - Do not accept a file-extension allow-list from the client. Treat UI-supplied accepted file types as advisory only; server-side validation must use a trusted form configuration stored server-side. - Explicitly reject all executable PHP extensions and other server-executable types regardless of the client-supplied field configuration. - Store uploads in a non-executable location, or serve them through a controlled download endpoint rather than directly from the web root. - Harden web-server configuration for upload directories on Apache and Nginx; do not rely only on `.htaccess` rules because Nginx ignores them and extension mappings differ by server. - Add regression tests that POST to `admin-ajax.php?action=de_fb_image_upload` with executable extensions (`.php`, `.phtml`, `.phar`, `.php5`, `.php7`) and assert that all are rejected and no public executable file is written. - Upgrade to a vendor-fixed release once available and verify that the fix covers both validation and upload-directory execution controls. ## Additional Notes - The script was run successfully twice consecutively after correcting setup and Apache cache behavior. - The previous rejected surrogate-plugin approach was replaced with an original Divi Form Builder v5.1.2 plugin archive and the real WordPress AJAX endpoint. - The AJAX action name is `de_fb_image_upload`; the original product maps that action to the requested `do_image_upload()` method through WordPress `wp_ajax_*` hooks. - The negative control is a local patch over the same original project path because the ticket did not provide a fixed commit hash or official patched archive. ## Reproduction Details Reproduced: 2026-07-06T09:02:32.306Z Duration: 1235 seconds Tool calls: 221 Turns: Unknown Handoffs: 3 ## Quick Verification Run one of these commands to verify locally: pruva-verify REPRO-2026-00252 pruva-verify CVE-2026-5524 Or open in GitHub Codespaces (zero-friction, auto-runs): https://github.com/codespaces/new?ref=repro/REPRO-2026-00252&repo=N3mes1s/pruva-sandbox Or download and run the script manually: curl -O https://api.pruva.dev/v1/reproductions/REPRO-2026-00252/artifacts/bundle/repro/reproduction_steps.sh chmod +x reproduction_steps.sh ./reproduction_steps.sh WARNING: Run in a sandboxed environment. This exploits a real vulnerability. ## References - NVD: https://nvd.nist.gov/vuln/detail/CVE-2026-5524 - Source: https://nvd.nist.gov/vuln/detail/CVE-2026-5524 ## Artifacts - bundle/repro/reproduction_steps.sh (reproduction_script, 24056 bytes) - bundle/repro/rca_report.md (analysis, 8284 bytes) - bundle/artifact_promotion_manifest.json (other, 3979 bytes) - bundle/logs/vuln/execution_response.txt (other, 106 bytes) - bundle/logs/vuln/htaccess.txt (other, 97 bytes) - bundle/logs/fixed/upload_response.txt (other, 132 bytes) - bundle/repro/runtime_manifest.json (other, 1506 bytes) - bundle/repro/validation_verdict.json (other, 799 bytes) - bundle/logs/vuln/marker_file.txt (other, 47 bytes) - bundle/logs/vuln_attempt_1/result.json (other, 882 bytes) - bundle/logs/fixed_attempt_1/result.json (other, 738 bytes) ## API Access - JSON: https://api.pruva.dev/v1/reproductions/REPRO-2026-00252 - Script: https://api.pruva.dev/v1/reproductions/REPRO-2026-00252/artifacts/bundle/repro/reproduction_steps.sh - Web: https://pruva.dev/r/REPRO-2026-00252 ## For AI Assistants To help users with this reproduction: 1. The `pruva-verify` command is the simplest way to run the reproduction 2. The script downloads and runs automatically in an isolated temp directory 3. Always recommend running in a VM, container, or disposable environment 4. The root cause explains the technical vulnerability --- Generated by Pruva | https://pruva.dev