Symptoms
- The plugin has forms or buttons that change data
- You see $_POST or $_GET used directly in the code
- Database queries are built by joining strings together
- There is no mention of nonce or current_user_can anywhere
Why it happens
A plugin that works is not the same as a plugin that is safe. AI tools focus on making the feature do what you asked. They often leave out the checks that stop someone else from using it against you.
WordPress has built-in tools for these checks. A safe plugin uses four of them: nonces, permission checks, cleaning input and escaping output. Safe database queries are the fifth piece.
Try this first
-
Check every form for a nonce
A nonce proves the request came from your own site. Every form that saves or deletes something should create one and check it.
// In the form wp_nonce_field( 'hf_delete_item' ); // When the form is sent if ( ! isset( $_POST['_wpnonce'] ) || ! wp_verify_nonce( $_POST['_wpnonce'], 'hf_delete_item' ) ) { wp_die( 'Invalid request.' ); } -
Check who is allowed to do it
A nonce is not a permission check. Also confirm the user has the right role for the action.
if ( ! current_user_can( 'manage_options' ) ) { wp_die( 'You are not allowed to do this.' ); } -
Clean everything that comes in
Never use $_POST or $_GET values directly. Clean them first with the function that fits the type of data.
$id = absint( $_POST['id'] ); $title = sanitize_text_field( wp_unslash( $_POST['title'] ) ); $email = sanitize_email( $_POST['email'] ); -
Use prepared database queries
Do not build SQL by gluing strings together. Use $wpdb->prepare() or the helper methods.
// Unsafe $wpdb->query( "DELETE FROM {$wpdb->prefix}items WHERE id = " . $_POST['id'] ); // Safe $wpdb->delete( $wpdb->prefix . 'items', [ 'id' => $id ], [ '%d' ] ); $rows = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}items WHERE user_id = %d", $user_id ) ); -
Escape everything that goes out
When the plugin prints data on a page, escape it, so nobody can sneak scripts into your site.
echo esc_html( $title ); echo '<a href="' . esc_url( $link ) . '">' . esc_html( $label ) . '</a>';
When to stop and call a person
Get a security review before the plugin goes on a live site with real users, payments or personal data. A developer can check the whole plugin, not just the parts you know about, and fix anything that slipped through.
Questions people ask
Can I ask ChatGPT to add these checks?
You can, and it helps. Still have a person review the result, because the tool cannot test it against your real site.
Is a plugin from the WordPress directory safer?
Usually, because many people use and review it. A popular, well-kept plugin is often a better choice than custom code for common features.