Revisjon av WordPress-plugins

Revisjon av WordPress-plugins

Oppdatert: 27. oktober 2026
19 min lesetid
Guide
500+ WP-prosjekter
Sikkerhetsrevisor

#Hvorfor AI-generert WordPress-plugin-kode er usikker

Å bruke store språkmodeller (LLMer) som GPT-4, Claude 3.5 Sonnet eller Gemini Pro til å skrive WordPress-plugin-kode har blitt en vanlig praksis for både utviklere og nettstedseiere. Løftet er utrolig tiltalende: beskriv den nødvendige funksjonaliteten på vanlig norsk, og AI genererer en klar-til-bruk PHP-fil på sekunder.

Problemet er imidlertid at språkmodeller utmerker seg på syntaks og struktur, men mangler operasjonell kontekst og en reell forståelse av sikkerhetsprinsipper i WordPress-økosystemet. Trent på enorme datasett med offentlig kode, arver de millioner av utdaterte, usikre og dårlig skrevne plugins publisert i løpet av de siste to tiårene. Som et resultat produserer AI ofte kode som er syntaktisk feilfri og funksjonell, men full av kritiske sikkerhetssårbarheter under panseret.

Som WordPress-utviklere må vi ta i bruk en streng “Zero Trust”-holdning overfor all kode skrevet av en AI. Denne guiden bryter ned de fem vanligste sikkerhetsfeilene vi observerer under revisjoner av AI-generert plugin-kode, og illustrerer dem med sårbare PHP-snutter ved siden av sikre, produksjonsklare refaktoreringer som samsvarer med WordPress Coding Standards (WPCS).


#1. is_admin() eller current_user_can() i WordPress

Kanskje den vanligste logiske feilen AI gjør når den prøver å sikre et endepunkt, er å stole på funksjonen is_admin() for å begrense adgangen til administratorer.

#Hvorfor is_admin() ikke sjekker administratorrettigheter

Til tross for navnet, verifiserer ikke is_admin() om den nåværende innloggede brukeren er en administrator. Den sjekker kun om den gjeldende forespørselen gjelder en administrasjonsside (som enhver URL som starter med /wp-admin/).

Hver AJAX-forespørsel sendt til /wp-admin/admin-ajax.php - enten den er initiert av en administrator, en innlogget abonnent med minimale rettigheter, eller en uautentisert anonym besøkende - vil føre til at is_admin() returnerer true.

#is_admin() som eneste sjekk ved lagring

// En AI-generert hook for å lagre innstillinger
add_action( 'admin_init', 'ai_save_plugin_settings' );
function ai_save_plugin_settings() {
    // AI antar feilaktig at dette begrenser adgangen til administratorer
    if ( is_admin() ) {
        if ( isset( $_POST['my_plugin_option'] ) ) {
            update_option( 'my_plugin_option', $_POST['my_plugin_option'] );
        }
    }
}

#Sjekk rettigheter med current_user_can()

For å verifisere de faktiske rettighetene til den innloggede brukeren, må du bruke funksjonen current_user_can(), og sende inn en spesifikk brukerrettighet i stedet for et rollenavn, for eksempel manage_options.

add_action( 'admin_init', 'secure_save_plugin_settings' );
function secure_save_plugin_settings() {
    // 1. Verifiser den nåværende brukerens faktiske rettigheter
    if ( ! current_user_can( 'manage_options' ) ) {
        wp_die( esc_html__( 'Du har ikke rettighet til å utføre denne handlingen.', 'secure-plugin' ) );
    }

    if ( isset( $_POST['my_plugin_option'] ) ) {
        // Bruk sanitysering på inndata (se avsnitt 4)
        $sanitized_value = sanitize_text_field( wp_unslash( $_POST['my_plugin_option'] ) );
        update_option( 'my_plugin_option', $sanitized_value );
    }
}

#2. Slik verifiserer du nonce i WordPress mot CSRF

Cross-Site Request Forgery (CSRF)-angrep lurer en autentisert brukers nettleser (f.eks. en administrator) til å utføre uautoriserte handlinger på et nettsted de er logget inn på. WordPress bruker kryptografiske token kalt nonces for å beskytte mot CSRF.

AI-generatorer utelater ofte opprettelse og verifisering av nonces i admin-skjemaer, AJAX-handlere og tilpassede REST API-endepunkter. Dette skjer fordi implementering av nonces krever koordinering av frontend-rendringslaget (HTML-skjemaet som inneholder nonce-feltet) med backend-prosesseringskontrolleren, noe som er vanskelig for LLMer å samkjøre på tvers av frakoblede kodegenereringer.

#AJAX-handler uten nonce-sjekk

// AI-generert AJAX-endepunktregistrering
add_action( 'wp_ajax_ai_delete_post', 'ai_delete_post_handler' );
function ai_delete_post_handler() {
    // AI sjekker rettigheter, men ignorerer CSRF fullstendig (ingen nonce-sjekk)
    if ( ! current_user_can( 'delete_posts' ) ) {
        wp_send_json_error( 'Uautorisert.' );
    }

    $post_id = intval( $_POST['post_id'] );
    wp_delete_post( $post_id );
    wp_send_json_success( 'Innlegg slettet.' );
}

#Verifiser nonce med check_ajax_referer()

Skjemaet må generere et nonce-felt ved hjelp av wp_nonce_field(), og den mottakende PHP-kontrolleren må verifisere tokenet ved hjelp av check_ajax_referer() eller wp_verify_nonce().

// I skjemaets rendringsfil eller javascript-payload:
// wp_nonce_field( 'delete_post_action', 'my_nonce_field' );

// Registrering av sikker AJAX-handler
add_action( 'wp_ajax_secure_delete_post', 'secure_delete_post_handler' );
function secure_delete_post_handler() {
    // 1. Verifiser CSRF-token tidlig
    check_ajax_referer( 'delete_post_action', 'my_nonce_field' );

    // 2. Verifiser brukerrettigheter
    if ( ! current_user_can( 'delete_posts' ) ) {
        wp_send_json_error( 'Uautorisert.' );
    }

    // 3. Valider og typiser inndatavariabler
    if ( ! isset( $_POST['post_id'] ) ) {
         wp_send_json_error( 'Mangler innleggs-ID.' );
    }

    $post_id = absint( $_POST['post_id'] );
    
    if ( wp_delete_post( $post_id ) ) {
        wp_send_json_success( 'Innlegget ble slettet.' );
    } else {
        wp_send_json_error( 'Feil under sletting av innlegget.' );
    }
}

#Hva en WordPress-nonce ikke beskytter mot

En nonce beviser bare at en forespørsel kom fra et skjema eller en lenke WordPress laget for denne brukeren. Nonce-kapitlet i WordPress sine sikkerhets-API-er sier at nonces aldri skal brukes til autentisering, autorisasjon eller tilgangskontroll, og derfor er rettighetssjekken ved siden av fortsatt obligatorisk. Tre egenskaper betyr noe i en gjennomgang. En nonce lages per bruker og per økt, så et token kopiert fra én konto feiler i en annen. Standard levetid er 24 timer, delt i to tikk, og WordPress godtar både nåværende og forrige tikk, så et gitt token virker i mellom 12 og 24 timer. En nonce er heller ikke engangs: samme verdi kan sendes på nytt innenfor dette vinduet, så den stopper ikke gjentatte forespørsler (replay). En generert handler som behandler en gyldig nonce som bevis på identitet, har CSRF-beskyttelse, men fortsatt ingen tilgangskontroll.


#3. SQL-injeksjonssårbarheter i $wpdb-spørringer

Når en plugin samhandler direkte med databasen i stedet for å bruke den opprinnelige WP_Query-wrapperen, bruker den det globale objektet $wpdb. Dessverre konstruerer LLMer ofte rå SQL-strenger ved direkte sammenslåing av brukerleverte variabler ($_POST, $_GET) i stedet for å parametrisere spørringen.

#Hvorfor sammenkoblet SQL er farlig

Å slå sammen rå variabler direkte inn i databasespørringer lar en angriper manipulere spørrestrukturen. Dette kan føre til uautorisert datagjenvinning (som hashede brukerpassord), sletting av databasen, eller eskalering av administratorrettigheter.

#SQL-spørring med sammenkoblet variabel

// Brukersøkfunksjon generert av AI
function ai_find_users_by_city( $city_name ) {
    global $wpdb;
    // Kritisk feil: direkte sammenslåing av spørrevariabelen
    $query = "SELECT * FROM {$wpdb->prefix}custom_users WHERE city = '" . $city_name . "'";
    return $wpdb->get_results( $query );
}

#Sikre spørringer med $wpdb->prepare()

Ingen rå variabler skal noen gang skrives direkte inn i SQL-strenger. Bruk i stedet metoden $wpdb->prepare(), som fungerer som en parametrisert spørremotor, typiserer og escaper verdier ved hjelp av formatspesifikasjoner (%s for strenger, %d for heltall, %f for desimaltall).

function secure_find_users_by_city( $city_name ) {
    global $wpdb;

    // 1. Bruk prepare() med formatspesifikasjoner
    $query = $wpdb->prepare(
        "SELECT * FROM {$wpdb->prefix}custom_users WHERE city = %s",
        $city_name
    );

    return $wpdb->get_results( $query );
}

Merk: Hvis variabelen $city_name kommer direkte fra brukerinput, må den fortsatt sanityseres med sanitize_text_field() før databasebehandling.


#4. Sanitysering og escaping i WordPress mot XSS

Cross-Site Scripting (XSS) er en av de vanligste sårbarhetene i WordPress-plugins. Det lar ondsinnet JavaScript-kode lagres i databasen eller speiles dynamisk, og kjøres i nettleseren til intetanende besøkende.

AI-modeller forveksler ofte sanitysering (rensing av data på vei inn) med escaping (sikring av data på vei ut). Selv om AI sanityserer inndata, viser den ofte variabler i maler uten å escape dem først, noe som etterlater nettstedet åpent for lagret XSS.

#Utdata uten escaping

// Feedback-løkke skrevet av AI
function ai_display_user_feedback() {
    $feedbacks = get_option( 'ai_user_feedback_list', [] );
    
    echo '<div class="feedback-list">';
    foreach ( $feedbacks as $feedback ) {
        // Kritisk feil: rå utdata uten escaping
        echo '<p class="feedback-item">' . $feedback['user_comment'] . '</p>';
    }
    echo '</div>';
}

#Escape utdata med esc_html()

Følg den grunnleggende WordPress-regelen: Sanitize Early, Escape Late (sanityser inndatavariabler umiddelbart; escape utdata umiddelbart før de sendes til nettleseren).

Velg riktig escaping-funksjon for konteksten:

  • esc_html() - for standard tekstnoder i HTML-elementer.
  • esc_attr() - for utdata i HTML-attributtverdier.
  • esc_url() - for utdata av lenker.
  • wp_kses() - når du må tillate spesifikke, sikre HTML-tagger (som strong, anchors).
function secure_display_user_feedback() {
    $feedbacks = get_option( 'secure_user_feedback_list', [] );
    
    echo '<div class="feedback-list">';
    foreach ( $feedbacks as $feedback ) {
        $comment = isset( $feedback['user_comment'] ) ? $feedback['user_comment'] : '';
        
        // 1. Escape utdata kontekstuelt umiddelbart før rendring
        echo '<p class="feedback-item">';
        echo esc_html( $comment );
        echo '</p>';
    }
    echo '</div>';
}

#5. Sikker filopplasting i WordPress med wp_handle_upload

Å tillate brukere å laste opp filer (som vedlegg i kontaktskjemaer eller opplasting av avatarer) er en av operasjonene med høyest risiko på et nettsted. En feil her lar angripere laste opp en .php-fil, noe som resulterer i ekstern kjøring av kode (RCE) og fullstendig serverkompromittering.

AI-genererte filbehandlere stoler ofte på opprinnelige PHP-kommandoer som move_uploaded_file() kombinert med svake filendelsessjekker (som enkel strengmatching), som er trivielle for angripere å omgå (f.eks. opplasting av filer med navnet malicious.php.jpg eller bruk av alternative etternavn som .phtml).

#Opplasting med move_uploaded_file() og filtypesjekk

// Opplastingsbehandler skrevet av AI
function ai_handle_avatar_upload() {
    if ( isset( $_FILES['avatar'] ) ) {
        $file_name = $_FILES['avatar']['name'];
        $ext = pathinfo( $file_name, PATHINFO_EXTENSION );
        
        // AI antar at denne filendelsessjekken er sikker
        if ( in_array( $ext, ['jpg', 'jpeg', 'png'] ) ) {
            $target = wp_upload_dir()['path'] . '/' . $file_name;
            move_uploaded_file( $_FILES['avatar']['tmp_name'], $target );
        }
    }
}

#Filopplasting med wp_handle_upload() og MIME-sjekk

Bruk aldri opprinnelig PHP move_uploaded_file() i WordPress. Bruk i stedet kjernefunksjonen wp_handle_upload(). Den utfører en robust MIME-type-sjekk (verifiserer filens faktiske signatur, ikke bare navnet), validerer opplastingsstatusen og integreres med WordPress-rettighetssystemet.

function secure_handle_avatar_upload() {
    // 1. Valider CSRF-tokenet
    if ( ! isset( $_POST['avatar_upload_nonce'] ) || ! wp_verify_nonce( $_POST['avatar_upload_nonce'], 'upload_avatar_action' ) ) {
        wp_die( esc_html__( 'Ugyldig sikkerhetstoken.', 'secure-plugin' ) );
    }

    // 2. Verifiser capability-sjekker
    if ( ! current_user_can( 'upload_files' ) ) {
        wp_die( esc_html__( 'Du har ikke rettighet til å laste opp filer.', 'secure-plugin' ) );
    }

    if ( isset( $_FILES['avatar'] ) ) {
        if ( ! function_exists( 'wp_handle_upload' ) ) {
            require_once ABSPATH . 'wp-admin/includes/file.php';
        }

        // 3. Tving begrensning av tillatte MIME-typer
        $allowed_mimes = [
            'jpg|jpeg' => 'image/jpeg',
            'png'      => 'image/png'
        ];

        $upload_overrides = [
            'test_form' => false,
            'mimes'     => $allowed_mimes
        ];

        // 4. Deleger opplastingsbehandling til kjernefunksjonen
        $movefile = wp_handle_upload( $_FILES['avatar'], $upload_overrides );

        if ( $movefile && ! isset( $movefile['error'] ) ) {
            $avatar_url = $movefile['url'];
            update_user_meta( get_current_user_id(), 'user_avatar', $avatar_url );
        } else {
            // Logg feilen sikkert
            error_log( 'Filopplasting feilet: ' . $movefile['error'] );
        }
    }
}

#6. Oppdiktede WordPress-funksjoner og falske Composer-pakker

En feiltype som er unik for generative modeller, er den selvsikre oppfinnelsen av kode som ikke finnes. Fordi en språkmodell forutser sannsynlige token i stedet for å slå opp i den faktiske WordPress-referansen, kaller den gjerne på funksjoner som aldri har vært en del av kjernen, som wp_verify_admin(), get_current_user_role() eller sanitize_all_input(). Navnene virker ekte fordi de følger WordPress’ navnekonvensjoner, og en fatal feil under kjøring er ofte det første tegnet på at noe er galt. Enda verre: en utvikler med dårlig tid “retter” den fatale feilen ved å skrive sin egen tynne innpakning rundt det hallusinerte navnet, og gjeninnfører dermed nøyaktig det hullet i sanitysering eller rettighetskontroll som den oppdiktede funksjonen lot som den lukket. AI kan på samme måte finne opp action- og filter-kroker som aldri utløses, slik at valideringskoden knyttet til dem blir død og gir en falsk følelse av trygghet.

Det samme mønsteret gjelder tredjeparts-avhengigheter. Når KI-en setter opp en composer.json eller foreslår require-linjer, kan den vise til pakker som ikke finnes på Packagist, eller enda farligere, til pakker med et navn som skiller seg fra et ekte bibliotek med bare ett tegn. Angripere utnytter denne “slopsquatting”-oppførselen ved å registrere de hallusinerte pakkenavnene på forhånd, slik at en uverifisert composer install trekker skadelig kode rett inn i pluginet.

To konkrete kontroller lukker dette gapet. For det første: sammenlign hver ukjente funksjon med den offisielle WordPress-kodereferansen på developer.wordpress.org før du stoler på den; finnes det ingen oppføring, behandle kallet som oppdiktet. For det andre: lås og gjennomgå hver avhengighet, bekreft at pakken finnes akkurat slik, kommer fra vedlikeholderen du forventer, og er låst til en gjennomgått versjon i stedet for et flytende versjonskrav.

// Hallusinert: en slik kjernefunksjon finnes ikke
if ( wp_current_user_is_admin() ) { /* ... */ }

// Ekte WordPress-API
if ( current_user_can( 'manage_options' ) ) { /* ... */ }

wp plugin verify-checksums sammenligner plugin-filene med sjekksummene publisert på WordPress.org (WP-CLI-dokumentasjonen), så den hjelper bare for plugins fra katalogen, ikke for en plugin AI-en har skrevet. For Composer-avhengigheter er en låst og gjennomgått composer.lock i diffen kontrollen, og composer why <pakke> viser hvilket krav som trakk inn en uventet pakke.


#7. Slik blokkerer du direkte tilgang til PHP-filer i en plugin

Hver PHP-fil i en plugin eller et tema bør nekte å kjøre når WordPress ikke er lastet. Plugin-håndboken anbefaler en sjekk av konstanten ABSPATH øverst i filen. Generert kode utelater ofte denne linjen, særlig i hjelpefiler modellen har skilt ut for lesbarhetens skyld.

#Hjelpefil uten ABSPATH-sjekk

<?php
function fjord_get_export_rows() {
    global $wpdb;
    return $wpdb->get_results( "SELECT * FROM {$wpdb->prefix}fjord_records" );
}

Et direkte kall til /wp-content/plugins/fjord-exporter/helpers.php kan kjøre filen utenfor WordPress og, avhengig av serveroppsettet, omgå innloggingen helt.

#ABSPATH-sjekk for PHP-filer i en plugin

<?php
if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

I gjennomgangen gjelder en enkel regel: hver .php-fil i plugin-mappen trenger disse linjene, også uninstall.php og kopierte bibliotekfiler. Mistenkelige er også genererte “API”-filer som selv laster WordPress med require 'wp-load.php'; og deretter ikke sjekker autentisering.


#8. REST API-ruter uten permission_callback

Genererte plugins eksponerer ofte data via register_rest_route() i stedet for admin-ajax.php. Tilgangsbeslutningen for en REST-rute ligger i ett argument, permission_callback, og modeller gjør det feil på to måter: de utelater det, eller de setter det til __return_true for å få en 401-feil i testingen til å forsvinne.

REST API-håndboken dekker begge tilfellene. Siden WordPress 5.5 utløser en rute registrert uten permission_callback en _doing_it_wrong-melding med rutens navn, så en manglende callback vises i feilsøkingsloggen på ethvert nettsted med WP_DEBUG slått på. __return_true er den dokumenterte verdien for endepunkter som skal være offentlige. Da kommer det ingen melding, så en skriverute som ved en feil er gjort offentlig, går ubemerket gjennom.

#Skriverute åpen for alle

register_rest_route( 'fjord/v1', '/settings', array(
    'methods'             => 'POST',
    'callback'            => 'fjord_update_settings',
    'permission_callback' => '__return_true',
) );

#Skriverute med rettighetssjekk og validerte argumenter

register_rest_route( 'fjord/v1', '/settings', array(
    'methods'             => WP_REST_Server::EDITABLE,
    'callback'            => 'fjord_update_settings',
    'permission_callback' => function () {
        return current_user_can( 'manage_options' );
    },
    'args'                => array(
        'label' => array(
            'type'              => 'string',
            'required'          => true,
            'validate_callback' => function ( $value ) {
                return is_string( $value ) && strlen( $value ) <= 100;
            },
            'sanitize_callback' => 'sanitize_text_field',
        ),
    ),
) );

For hvert argument returnerer validate_callback true eller false, og REST-serveren avviser ugyldige data med en feil klienten kan lese, mens sanitize_callback renser verdien før den når callbacken din. I gjennomgangen lister du opp hvert kall til register_rest_route() og leser permission_callback først: __return_true på en rute som tar imot mer enn GET, trenger en skriftlig begrunnelse. For forespørsler fra nettleseren som autentiseres med informasjonskapsel, legger kapitlet om autentisering til én regel: uten en wp_rest-nonce i headeren X-WP-Nonce setter API-et gjeldende bruker til 0. Et frontend-skript som bare “virker” fordi det hopper over nonce, kaller i realiteten ruten som en utlogget besøkende.


#Slik reviderer du AI-generert plugin-kode

For å distribuere AI-generert kode på en sikker måte, må ingeniørteamet ditt etablere en systematisk gjennomgangsprosess. Implementer disse tre trinnene før du skyver genererte ressurser til produksjon:

#Trinn 1: Automatiser statisk analyse (PHPCS)

Konfigurer WordPress Coding Standards (WPCS) for PHP_CodeSniffer-verktøyet. Det skanner filer og flagger manglende sanitysering, utelatte nonces og uescapede variabler automatisk.

# Skann en generert plugin-fil med WordPress-standarder
vendor/bin/phpcs --standard=WordPress-Extra path/to/generated-plugin.php

#Hvilke WPCS-regler fanger sikkerhetsmønstrene

WordPress Coding Standards 3.x installeres bare via Composer og krever PHP 7.2 eller nyere; WordPressCS-repositoriet publiserte versjon 3.4.1 i juli 2026.

composer config allow-plugins.dealerdirect/phpcodesniffer-composer-installer true
composer require --dev wp-coding-standards/wpcs:"^3.0"

WordPress-Extra inneholder WordPress-Core pluss anbefalt praksis. Sikkerhetsreglene (sniffs) ligger i to grupper. WordPress.Security.NonceVerification rapporterer lesing av $_POST og $_GET uten nonce-sjekk først, WordPress.Security.ValidatedSanitizedInput rapporterer superglobale variabler brukt uten isset(), wp_unslash() og en sanityseringsfunksjon, WordPress.Security.EscapeOutput rapporterer utdata uten escaping, og WordPress.Security.SafeRedirect rapporterer wp_redirect() der en trygg videresending hører hjemme. På databasesiden rapporterer WordPress.DB.PreparedSQL og WordPress.DB.PreparedSQLPlaceholders SQL med innskutte variabler og feil i plassholdere, og WordPress.DB.DirectDatabaseQuery merker direkte spørringer for gjennomgang. Slik kjører du bare sikkerhetsreglene mot en generert plugin:

vendor/bin/phpcs --standard=WordPress --sniffs=WordPress.Security.NonceVerification,WordPress.Security.ValidatedSanitizedInput,WordPress.Security.EscapeOutput,WordPress.DB.PreparedSQL path/to/generated-plugin/

Ingen regel kan avgjøre om en handler krever riktig rettighet, så kontrollen av current_user_can() i trinn 2 forblir manuell.

#Trinn 2: Gjennomfør en manuell kodegjennomgang

Gjennomgå hver handler som utfører HTTP-spørringer, databasetransaksjoner, AJAX-anrop eller REST API-tilkoblinger mot følgende flytskjema:

graph TD
    A["Motta AI-skrevet plugin-kode"] --> B{"Godtar den brukerinput?"}
    B -- Ja --> C["Sjekk for Nonce og Capability-sjekker"]
    B -- Nei --> D{"Modifiserer den databasen?"}
    
    C --> C1["Implementer check_ajax_referer() / CSRF-validering"]
    C --> C2["Implementer current_user_can() rettighetssjekk"]
    C1 --> D
    C2 --> D
    
    D -- Ja --> E["Sjekk for $wpdb->prepare() bruk"]
    D -- Nei --> F{"Sender den utdata til nettleseren?"}
    
    E --> E1["Implementer parametriserte SQL-variabler"]
    E1 --> F
    
    F -- Ja --> G["Verifiser esc_html(), esc_attr(), eller esc_url()"]
    F -- Nei --> H["Fortsett til integrasjonstesting"]
    
    G --> G1["Implementer kontekstuell utdata-escaping"]
    G1 --> H

#Trinn 3: Kjør tester med lave rettigheter

Verifiser kodens adgangsgrenser. Logg inn som en bruker med rollen “Abonnent” og utløs pluginens REST- eller AJAX-handlinger direkte via curl eller Postman. Hvis serveren utfører modifikasjoner eller avslører databasedata, mangler rettighetslagene.

Hvis en AI-agent gjør en del av denne gjennomgangen, viser Cloudflares pakke security-audit, publisert under MIT-lisens (README lest i oktober 2026), hvordan funnene holdes etterprøvbare. Hvert mistenkt funn går til en ny kontrollagent som prøver å motbevise det, så agenten som sjekker et funn, er aldri den som fant det. Et spor som ikke kan bevises, blir stående merket needs_validation, uten alvorlighetsgrad, og havner ikke i rapporten som et sikkerhetshull. Mangler et ekstra forsvarslag mens det første allerede stopper angrepet, regnes det som et herdingsråd. Cloudflare legger til at én enkelt kjøring i deres egne tester fant omtrent halvparten av sårbarhetene som gjentatte kjøringer fant til sammen. For en generert plugin er én AI-gjennomgang derfor et utgangspunkt; PHPCS, sjekklisten for hver handler og testene med lave rettigheter gjelder fortsatt.

Oppdatering . To kontroller til hører hjemme på denne sjekklisten, og WooCommerce-utvidelser trenger begge. Den første gjelder visning av et innlegg eller produkt ut fra ID. Hver funksjon som tar en innleggs- eller produkt-ID fra en forespørsel eller et kortkodeattributt, må sjekke status, synlighet og passord før noe skrives ut, ellers viser et utkast eller et privat eller passordbeskyttet produkt navn, pris eller bilde gjennom en kortkode, en hurtigvisning eller en sammenligningsliste. Søk i PHP-koden etter get_post(, wc_get_product( og shortcode_atts(, følg hver ID fram til utskriften, og se etter en kontroll av status og synlighet (for eksempel current_user_can( 'read_post', $id ) eller $product->is_visible()) pluss post_password_required(). Den andre kontrollen gjelder JavaScript. WooCommerce sender variant- og handlekurvhendelsene sine gjennom jQuery, så en nativ addEventListener på navn som found_variation eller updated_cart_totals utløses aldri. Søk etter disse navnene i JavaScript-koden, og sjekk at lytterne går gjennom jQuery, for eksempel jQuery( document.body ).on( 'updated_cart_totals', ... ).


#Slik kjører du Plugin Check på en AI-generert plugin

Plugin Check er verktøyet WordPress.org bruker for å teste plugins mot kravene i katalogen, og det er like nyttig på en privat plugin som aldri skal sendes inn. Versjon 2.1.0 kom i august 2026. Det har to moduser: statiske kontroller som leser koden, delvis via PHP_CodeSniffer-regler og delvis via egne regler, og kjøretidskontroller som aktiverer pluginen og kjører deler av den. Prosjektet fraråder å kjøre det på et produksjonsnettsted, så installer det på et testmiljø.

wp plugin check fjord-exporter
wp plugin check fjord-exporter --categories=security --format=csv --fields=code,type,severity,message
wp plugin check fjord-exporter --require=./wp-content/plugins/plugin-check/cli.php

Fra WP-CLI kjøres bare de statiske kontrollene som standard; den tredje kommandoen laster cli.php slik at kjøretidskontrollene også kjøres. Listen over kontroller plasserer fem av dem i kategorien security, og de samsvarer med mønstrene i denne guiden:

KontrollHva den rapportererMønster i denne guiden
direct_file_accessPHP-filer uten ABSPATH-sjekkdirekte filtilgang
late_escapingutdata til nettleseren uten escapingXSS
direct_dbverdier uten escaping i direkte databasespørringerSQL-injeksjon
direct_db_queriesdirekte databasespørringer genereltSQL-injeksjon
safe_redirectwp_redirect() i stedet for wp_safe_redirect()åpen videresending

PHPCS-regelsettet bak kontrollen plugin_review_phpcs laster i tillegg WPCS-reglene for nonce, sanitysering av input og forberedt SQL, men det hører til kategorien plugin_repo, så --categories=security skjuler disse funnene. Én kontroll gjelder spesielt generert kode: file_type rapporterer AI-utviklingsmapper som .cursor, .claude, .aider, .continue, .windsurf og .ai som er blitt liggende i pluginen fordi plugin-mappen var arbeidsmappen til en kodeassistent. Hvert funn har en type (ERROR eller WARNING) og en alvorlighetsgrad fra 1 til 10. Plugin Check vet ikke hvilken rettighet en handler bør kreve, så verktøyet korter ned den manuelle gjennomgangen uten å erstatte den.

#Når du bør patche en AI-plugin og når hele nettstedet må reddes

Lokale hull (én AJAX-handler, ett adminskjema) er verdt å patche etter gjennomgang. Når de samme fem mønstrene går igjen i flere genererte filer, når oppdiktede funksjoner er koblet inn i produksjonsstier, eller når plugins valgt av AI har aktive CVE-er i tillegg til dårlig egenutviklet kode, slutter du å patche isolert. Revisjonen for redning av AI-bygde nettsider gir en tydelig fordeling mellom behold, skriv om og fjern, slik at du ikke betaler for full ombygging når redning holder, og ikke patcher i det uendelige når fundamentet ikke bærer. Når stacken i tillegg har over tretti plugins og ødelagte Core Web Vitals, kombinerer du koderevisjonen med Core Web Vitals-redning for AI-bygde nettsider.

Prisen for redning og revisjon er individuell og settes etter denne gjennomgangen. Kontakt oss med URL-en til pluginen eller nettstedet og hvordan koden ble generert.


#Sammendrag og anbefalinger

Kunstig intelligens er en kraftig akselerator for å skrive kode, men den kan ikke overta ingeniøransvar. Behandle all AI-skrevet kode som om den var skrevet av en uerfaren praktikant.

Sørg for at du implementerer robuste capability-sjekker (current_user_can()), CSRF-verifisering (wp_verify_nonce()), databaseparametrisering ($wpdb->prepare()), sanitysering av inndata og sen escaping av utdata. Ved å kombinere disse kjernepraksisene med statiske analyseverktøy, kan du skrive WordPress-kode raskere samtidig som du opprettholder en helt sikker applikasjon.

Neste steg

Gjør artikkelen om til faktisk implementering

Denne blokken styrker intern lenking og sender leseren videre til de mest relevante tjenestene og innholdet.

Ofte stilte spørsmål

Praktiske svar for å bruke temaet i faktisk arbeid.

Hvorfor er AI-generert WordPress-plugin-kode ofte usikker#
AI-generatorer (LLMer) er trent på offentlig tilgjengelig kode, og mye av denne inneholder utdaterte eller usikre mønstre skrevet i løpet av de siste 15 årene. AI mangler dessuten operasjonell kontekst for WordPress-kjøring, noe som resulterer i syntaktisk korrekt PHP-kode som helt utelater kritiske rettighetssjekker og CSRF-validering (nonces).
Hva er forskjellen på is_admin() og current_user_can() for sikkerhet#
Funksjonen is_admin() sjekker kun om den gjeldende forespørselen gjelder en administrasjonsside (som /wp-admin/) og verifiserer ikke brukerrettigheter. Å bruke den til adgangskontroll lar enhver innlogget bruker (inkludert abonnenter) kjøre koden. Sikker adgangskontroll krever current_user_can('manage_options') eller lignende.
Hvordan introduserer AI SQL-injeksjonssårbarheter i WordPress-kode#
Det vanligste problemet er direkte sammenslåing av brukerinput-variabler ($_POST eller $_GET) i SQL-spørrestrenger, f.eks. $wpdb->query("SELECT * FROM table WHERE id = $id"). For å forhindre SQL-injeksjon må alle dynamiske spørringer kjøres via $wpdb->prepare() med riktige formatspesifikasjoner (%d for heltall, %s for strenger).
Hva er sanitysering og escaping i WordPress-standarder#
Sanitysereing (som sanitize_text_field) renser inndata før de lagres i databasen. Escaping (som esc_html, esc_attr, esc_url) sikrer utdata umiddelbart før de rendres i nettleseren, noe som forhindrer Cross-Site Scripting (XSS)-angrep. AI-generert kode forveksler ofte disse to praksisene eller glemmer dem helt.
Hva er hallusinerte WordPress-funksjoner i AI-generert kode#
Hallusinerte funksjoner er kall som en språkmodell finner opp, og som aldri har vært en del av WordPress-kjernen eller et installert plugin, som wp_verify_admin() eller sanitize_all_input(). De følger WordPress' navnekonvensjoner tett nok til å se ekte ut, men utløser en fatal feil under kjøring. Sammenlign alltid ukjente funksjoner med den offisielle kodereferansen på developer.wordpress.org, og bekreft at hver Composer-avhengighet AI foreslår, faktisk finnes på Packagist før du kjører composer install.

Trenger du FAQ tilpasset bransje og marked? Jeg lager en versjon som støtter dine forretningsmål.

Ta kontakt

Relaterte artikler