Ga naar inhoud
Kritieke uploadkwetsbaarheid in Elementor Pro opgelost in versie 4.2.2
Sophie de Vries
Sophie de Vries 20 August 2026 · 9 min leestijd

Kritieke uploadkwetsbaarheid in Elementor Pro opgelost in versie 4.2.2

Elementor Pro tot en met versie 4.2.1 bevat een kritieke kwetsbaarheid voor het uploaden van willekeurige bestanden. Een aanvaller zonder account kan daardoor een uitvoerbaar PHP-bestand op een kwetsbare WordPress-site plaatsen en vervolgens code op de server uitvoeren. Update Elementor Pro daarom zo snel mogelijk naar versie 4.2.2 of nieuwer.

Direct bijwerken

CVE-2026-32475 heeft een CVSS-score van 9,8 op 10. De kwetsbaarheid treft Elementor Pro 4.2.1 en ouder; Elementor Pro 4.2.2 verhelpt het probleem.

Wanneer een site kwetsbaar is

De fout zit in de Form-widget van Elementor Pro, die bestandsvelden ondersteunt. Misbruik vereist dat je een gepubliceerde pagina hebt met zo’n formulier én dat minstens één File Upload-veld niet verplicht is. Een bezoeker hoeft niet ingelogd te zijn om de kwetsbaarheid te misbruiken.

Een aanvaller stuurt een uploadveld als array met twee onderdelen. Het eerste onderdeel bevat geen bestand en veroorzaakt UPLOAD_ERR_NO_FILE; het tweede bevat een PHP-payload met een zelfgekozen bestandsextensie. Door een fout in de validatie controleert Elementor Pro dat tweede bestand niet.

  • CVE-ID: CVE-2026-32475
  • Ernst: 9,8/10 (kritiek)
  • Getroffen software: Elementor Website Builder Pro (elementor-pro)
  • Getroffen versies: 4.2.1 en ouder
  • Opgeloste versie: 4.2.2
  • Voorwaarde voor misbruik: een gepubliceerd Elementor Pro-formulier met minstens één niet-verplicht File Upload-veld

De fout in de validatielus

Niet-ingelogde bezoekers bereiken de formulierverwerking via ajax_send_form() in de klasse Ajax_Handler. Elementor Pro verpakt de ingestuurde gegevens en bestanden daarna in een Form_Record-object. Voor bestandsvelden roept de plugin achtereenvolgens validation() en process_field() aan in ElementorProModulesFormsFieldsUpload.

De validatielus hoort een leeg uploadslot over te slaan met continue. In de kwetsbare versies gebruikt de code echter return. Zodra het eerste arrayelement UPLOAD_ERR_NO_FILE bevat en het veld niet verplicht is, stopt de hele functie. Elementor Pro voert daarna geen controle op extensie of bestandstype via is_file_type_valid() en ook geen bestandsgroottecontrole meer uit voor de volgende bestanden in hetzelfde veld.

public function validation( $field , ClassesForm_Record $record , ClassesAjax_Handler $ajax_handler ) {
    static $upload_errors = false;

    if ( ! $upload_errors ) {
        $upload_errors = [
            UPLOAD_ERR_OK => esc_html__( 'There is no error, the file uploaded with success.' , 'elementor-pro' ),
            /* translators: 1: upload_max_filesize, 2: php.ini */
            UPLOAD_ERR_INI_SIZE => sprintf( esc_html__( 'The uploaded file exceeds the %1$s directive in %2$s.' , 'elementor-pro' ), 'upload_max_filesize' , 'php.ini' ),
            /* translators: %s: MAX_FILE_SIZE */
            UPLOAD_ERR_FORM_SIZE => sprintf( esc_html__( 'The uploaded file exceeds the %s directive that was specified in the HTML form.' , 'elementor-pro' ), 'MAX_FILE_SIZE' ),
            UPLOAD_ERR_PARTIAL => esc_html__( 'The uploaded file was only partially uploaded.' , 'elementor-pro' ),
            UPLOAD_ERR_NO_FILE => esc_html__( 'No file was uploaded.' , 'elementor-pro' ),
            UPLOAD_ERR_NO_TMP_DIR => esc_html__( 'Missing a temporary folder.' , 'elementor-pro' ),
            UPLOAD_ERR_CANT_WRITE => esc_html__( 'Failed to write file to disk.' , 'elementor-pro' ),
            /* translators: %s: phpinfo() */
            UPLOAD_ERR_EXTENSION => sprintf( esc_html__( 'A PHP extension stopped the file upload. PHP does not provide a way to ascertain which extension caused the file upload to stop; examining the list of loaded extensions with %s may help.' , 'elementor-pro' ), 'phpinfo()' ),
        ];
    }

    $this->fix_file_indices();
    $id = $field[ 'id' ];
    $files = Utils::_unstable_get_super_global_value( $_FILES, 'form_fields' );

    if ( ! empty( $field[ 'max_files' ] ) ) {
        if ( count( $files[ $id ] ) > $field[ 'max_files' ] ) {
            $error_message = sprintf(
                /* translators: %d: Maximum number of allowed files. */
                _n( 'You can upload only %d file.', 'You can upload up to %d files.', intval( $field[ 'max_files' ] ), 'elementor-pro' ),
                intval( $field[ 'max_files' ] )
            );
            $ajax_handler->add_error( $id, $error_message );
            return;
        }
    }

    foreach ( $files[ $id ] as $index => $file ) {
        // not uploaded
        if ( ! $field[ 'required' ] && UPLOAD_ERR_NO_FILE === $file[ 'error' ] ) {
            return;
        }

        // is the file required and missing?
        if ( $field[ 'required' ] && UPLOAD_ERR_NO_FILE === $file[ 'error' ] ) {
            $ajax_handler->add_error( $id, $upload_errors[ $file[ 'error' ] ] );
            return;
        }

        // Has any error with upload the file?
        if ( $file[ 'error' ] > UPLOAD_ERR_OK ) {
            $ajax_handler->add_error( $id, $upload_errors[ $file[ 'error' ] ] );
            return;
        }

        // valid file type?
        if ( ! $this->is_file_type_valid( $field, $file ) ) {
            $ajax_handler->add_error( $id, esc_html__( 'This file type is not allowed.', 'elementor-pro' ) );
        }

        // allowed file size?
        if ( ! $this->is_file_size_valid( $field, $file ) ) {
            $ajax_handler->add_error( $id, esc_html__( 'This file exceeds the maximum allowed size.', 'elementor-pro' ) );
        }
    }
}

Waarom een PHP-bestand toch op de server belandt

De functie process_field() behandelt hetzelfde uploadveld na de voortijdig afgebroken validatie. Deze functie gebruikt bij een leeg eerste onderdeel wél continue. Daardoor slaat zij het lege element over en verwerkt zij alsnog het tweede, niet-gevalideerde bestand.

process_field() haalt de extensie rechtstreeks uit de bestandsnaam die de cliënt aanlevert. Daarna schrijft de functie het bestand met die extensie naar de schijf. Een bestand met de extensie .php komt zo terecht in /wp-content/uploads/elementor/forms/; een aanvaller kan dat bestand vervolgens opvragen om de PHP-payload op de server uit te voeren. Dit maakt een volledige siteovername mogelijk, onder meer met webshells.

public function process_field( $field , ClassesForm_Record $record , ClassesAjax_Handler $ajax_handler ) {
    $id = $field[ 'id' ];
    $files = Utils::_unstable_get_super_global_value( $_FILES, 'form_fields' );

    foreach ( $files[ $id ] as $index => $file ) {
        if ( UPLOAD_ERR_NO_FILE === $file[ 'error' ] ) {
            continue;
        }

        $uploads_dir = $this->get_ensure_upload_dir();
        $file_extension = pathinfo( $file[ 'name' ], PATHINFO_EXTENSION );
        $filename = uniqid() . '.' . $file_extension;
        $filename = wp_unique_filename( $uploads_dir, $filename );
        $new_file = trailingslashit( $uploads_dir ) . $filename;

        if ( is_dir( $uploads_dir ) && is_writable( $uploads_dir ) ) {
            $move_new_file = Plugin::instance()->php_api->move_uploaded_file( $file[ 'tmp_name' ], $new_file );

            if ( false !== $move_new_file ) {
                // Set correct file permissions.
                $perms = 0644;
                @chmod( $new_file, $perms );
                $record->add_file( $id, $index, [
                    'path' => $new_file,
                    'url' => $this->get_file_url( $filename ),
                ] );
            } else {
                $ajax_handler->add_error( $id, esc_html__( 'There was an error while trying to upload your file.', 'elementor-pro' ) );
            }
        } else {
            $ajax_handler->add_admin_error_message( esc_html__( 'Upload directory is not writable or does not exist.', 'elementor-pro' ) );
        }
    }
}

Patch en tijdlijn

Een beveiligingsonderzoeker meldde de kwetsbaarheid op 24 juli 2026 via het bugbountyprogramma van Wordfence. Na validatie van het proof of concept volgde de melding aan Elementor op 27 juli. Op 2 augustus liet Elementor weten dat een andere onderzoeker dezelfde kwetsbaarheid ook had gemeld en dat het team aan een patch werkte.

Elementor bracht op 19 augustus 2026 versie 4.2.2 uit, die de fout volledig oplost. Voor deze kwetsbaarheid geldt de CVE die al aan de andere melding was toegewezen: CVE-2026-32475.

Controleer je Elementor Pro-versie

Open het WordPress-dashboard en controleer welke versie van Elementor Pro actief is. Draait je site versie 4.2.1 of ouder, installeer dan onmiddellijk versie 4.2.2 of een latere versie. Controleer ook alle beheerde sites met Elementor Pro, vooral sites waarop openbare formulieren bestandsuploads accepteren.

Sophie de Vries

Sophie de Vries

Hoofdredacteur van het Nederlandse team, evangelist voor toegankelijkheid en webstandaarden. Ik geloof in het open web en inclusief design. WCAG-expert.

Alle berichten

Word lid van de HelloWP-community!

Chat met ons over WordPress en webontwikkeling en deel ervaringen met andere ontwikkelaars.

- leden
- online
Deelnemen

We gebruiken cookies om je ervaring te verbeteren. Door verder te gaan, ga je akkoord met ons Cookiebeleid.