Skip to main content

Security Best Practices

This guide covers essential security practices when using WP LLM generated code in WordPress applications. Learn how to ensure your AI-generated code follows WordPress security standards and protects against common vulnerabilities.

🛡️ Security Fundamentals

WordPress Security Principles

Common Vulnerabilities

🔧 WP LLM Security Best Practices

Input Sanitization

php
/**
 * Comprehensive input sanitization example
 * 
 * This function demonstrates proper input sanitization techniques:
 * - Uses WordPress sanitization functions for different data types
 * - Implements proper file upload handling
 * - Follows WordPress security best practices
 * - Includes error handling and validation
 * 
 * @see https://developer.wordpress.org/plugins/security/securing-input/
 * @see https://developer.wordpress.org/reference/functions/sanitize_text_field/
 * @see https://developer.wordpress.org/reference/functions/sanitize_email/
 * @see https://developer.wordpress.org/reference/functions/wp_handle_upload/
 */
function handle_user_input() {
    // Sanitize text input - removes HTML tags and encodes special characters
    $title = sanitize_text_field($_POST['title']);
    
    // Sanitize email - validates email format and removes invalid characters
    $email = sanitize_email($_POST['email']);
    
    // Sanitize URL - validates URL format and removes dangerous protocols
    $website = esc_url_raw($_POST['website']);
    
    // Sanitize textarea - removes HTML tags but preserves line breaks
    $description = sanitize_textarea_field($_POST['description']);
    
    // Sanitize array of data - applies sanitization to each element
    $tags = array_map('sanitize_text_field', $_POST['tags']);
    
    // Validate and sanitize file upload with security checks
    if (!empty($_FILES['image'])) {
        $file = wp_handle_upload($_FILES['image'], array(
            'test_form' => false,
            'mimes' => array(
                'jpg|jpeg' => 'image/jpeg',
                'png' => 'image/png',
                'gif' => 'image/gif'
            )
        ));
        
        if (!isset($file['error'])) {
            $image_url = $file['url'];
        } else {
            // Handle upload error
            error_log('File upload failed: ' . $file['error']);
        }
    }
    
    return array(
        'title' => $title,
        'email' => $email,
        'website' => $website,
        'description' => $description,
        'tags' => $tags,
        'image_url' => isset($image_url) ? $image_url : ''
    );
}

Output Escaping

php
/**
 * Comprehensive output escaping example
 * 
 * This function demonstrates proper output escaping techniques:
 * - Uses appropriate escaping functions for different contexts
 * - Implements safe HTML output with wp_kses
 * - Follows WordPress security best practices
 * - Prevents XSS attacks
 * 
 * @param int $user_id WordPress user ID
 * @see https://developer.wordpress.org/plugins/security/securing-output/
 * @see https://developer.wordpress.org/reference/functions/esc_html/
 * @see https://developer.wordpress.org/reference/functions/wp_kses/
 */
function display_user_data($user_id) {
    $user = get_user_by('id', $user_id);
    
    if ($user) {
        // Escape for HTML output - prevents XSS in HTML content
        echo '<h2>' . esc_html($user->display_name) . '</h2>';
        
        // Escape for HTML attributes - prevents XSS in attributes
        echo '<img src="' . esc_attr($user->avatar_url) . '" alt="' . esc_attr($user->display_name) . '">';
        
        // Escape for URLs - validates and escapes URL output
        echo '<a href="' . esc_url($user->user_url) . '">Visit Website</a>';
        
        // Escape for JavaScript - prevents XSS in JavaScript contexts
        echo '<script>var userName = "' . esc_js($user->display_name) . '";</script>';
        
        // Allow safe HTML with wp_kses - permits only specified HTML tags
        $allowed_html = array(
            'p' => array(),
            'br' => array(),
            'strong' => array(),
            'em' => array(),
            'a' => array(
                'href' => array(),
                'title' => array(),
                'target' => array()
            )
        );
        
        echo wp_kses($user->description, $allowed_html);
    }
}

Nonce Verification

php
/**
 * Secure form handling with nonce verification
 * 
 * This example demonstrates CSRF protection using WordPress nonces:
 * - Implements nonce creation and verification
 * - Includes capability checks
 * - Uses proper sanitization
 * - Follows WordPress security best practices
 * 
 * @see https://developer.wordpress.org/plugins/security/nonces/
 * @see https://developer.wordpress.org/reference/functions/wp_verify_nonce/
 * @see https://developer.wordpress.org/reference/functions/current_user_can/
 */
function handle_form_submission() {
    // Verify nonce to prevent CSRF attacks
    if (!wp_verify_nonce($_POST['_wpnonce'], 'my_form_action')) {
        wp_die('Security check failed', 'Security Error', array('response' => 403));
    }
    
    // Check user capabilities before processing
    if (!current_user_can('edit_posts')) {
        wp_die('Insufficient permissions', 'Access Denied', array('response' => 403));
    }
    
    // Process form data with proper sanitization
    $title = sanitize_text_field($_POST['title']);
    $content = wp_kses_post($_POST['content']); // Allows safe HTML
    
    // Validate required fields
    if (empty($title)) {
        wp_die('Title is required', 'Validation Error', array('response' => 400));
    }
    
    // Save data securely
    $post_id = wp_insert_post(array(
        'post_title' => $title,
        'post_content' => $content,
        'post_status' => 'publish',
        'post_author' => get_current_user_id()
    ));
    
    if (is_wp_error($post_id)) {
        wp_die('Failed to save post', 'Database Error', array('response' => 500));
    }
    
    return $post_id;
}

// Render secure form with nonce
function render_form() {
    ?>
    <form method="post" action="">
        <?php wp_nonce_field('my_form_action'); ?>
        <input type="text" name="title" required>
        <textarea name="content"></textarea>
        <input type="submit" value="Submit">
    </form>
    <?php
}

REST API Security

php
/**
 * Secure REST API endpoint implementation
 * 
 * This example demonstrates secure REST API development:
 * - Implements proper permission callbacks
 * - Uses nonce verification for API requests
 * - Includes input validation and sanitization
 * - Follows WordPress REST API security best practices
 * 
 * @see https://developer.wordpress.org/rest-api/
 * @see https://developer.wordpress.org/rest-api/extending-the-rest-api/
 * @see https://developer.wordpress.org/rest-api/using-the-rest-api/authentication/
 */
function register_secure_api_endpoint() {
    register_rest_route('wp-llm/v1', '/secure-data', array(
        'methods' => 'POST',
        'callback' => 'handle_secure_api_request',
        'permission_callback' => function() {
            // Check user capabilities and nonce verification
            return current_user_can('edit_posts') && 
                   wp_verify_nonce($_POST['_wpnonce'], 'api_action');
        },
        'args' => array(
            'title' => array(
                'required' => true,
                'sanitize_callback' => 'sanitize_text_field',
                'validate_callback' => function($param) {
                    return !empty($param) && strlen($param) <= 100;
                }
            ),
            'content' => array(
                'required' => false,
                'sanitize_callback' => 'wp_kses_post'
            )
        )
    ));
}

function handle_secure_api_request($request) {
    // Additional security checks
    if (!current_user_can('edit_posts')) {
        return new WP_Error(
            'insufficient_permissions', 
            'Insufficient permissions', 
            array('status' => 403)
        );
    }
    
    $title = $request->get_param('title');
    $content = $request->get_param('content');
    
    // Process and return secure response
    return rest_ensure_response(array(
        'success' => true,
        'data' => array(
            'title' => $title,
            'content' => $content
        )
    ));
}

🚨 Advanced Security Techniques

SQL Injection Prevention

php
/**
 * Safe database queries with SQL injection prevention
 * 
 * This example demonstrates secure database operations:
 * - Uses prepared statements with $wpdb->prepare()
 * - Implements proper parameter validation
 * - Shows alternative WP_Query approach
 * - Follows WordPress database security best practices
 * 
 * @param string $category Category slug to filter by
 * @return array|object Database results
 * @see https://developer.wordpress.org/reference/classes/wpdb/prepare/
 * @see https://developer.wordpress.org/reference/classes/wp_query/
 */
function get_secure_posts($category = '') {
    global $wpdb;
    
    // Use prepared statements to prevent SQL injection
    $query = $wpdb->prepare(
        "SELECT * FROM {$wpdb->posts} p 
         JOIN {$wpdb->term_relationships} tr ON p.ID = tr.object_id 
         JOIN {$wpdb->term_taxonomy} tt ON tr.term_taxonomy_id = tt.term_taxonomy_id 
         JOIN {$wpdb->terms} t ON tt.term_id = t.term_id 
         WHERE tt.taxonomy = %s AND t.slug = %s AND p.post_status = %s",
        'category',
        $category,
        'publish'
    );
    
    return $wpdb->get_results($query);
}

// Alternative using WP_Query (recommended for most cases)
function get_secure_posts_wp_query($category = '') {
    return new WP_Query(array(
        'category_name' => sanitize_title($category),
        'post_status' => 'publish',
        'posts_per_page' => 10
    ));
}

File Upload Security

php
/**
 * Secure file upload handling with comprehensive security checks
 * 
 * This function implements secure file upload processing:
 * - Validates file types and sizes
 * - Implements proper error handling
 * - Uses WordPress file handling functions
 * - Follows security best practices
 * 
 * @return string|WP_Error Upload URL or error object
 * @see https://developer.wordpress.org/reference/functions/wp_handle_upload/
 * @see https://developer.wordpress.org/reference/functions/wp_check_filetype/
 */
function handle_secure_file_upload() {
    // Verify nonce for CSRF protection
    if (!wp_verify_nonce($_POST['_wpnonce'], 'file_upload_action')) {
        wp_die('Security check failed', 'Security Error', array('response' => 403));
    }
    
    // Check user capabilities
    if (!current_user_can('upload_files')) {
        wp_die('Insufficient permissions', 'Access Denied', array('response' => 403));
    }
    
    $file = $_FILES['upload_file'];
    
    // Validate file type
    $allowed_types = array('jpg', 'jpeg', 'png', 'gif');
    $file_extension = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
    
    if (!in_array($file_extension, $allowed_types)) {
        wp_die('Invalid file type. Allowed types: ' . implode(', ', $allowed_types));
    }
    
    // Check file size (5MB limit)
    $max_size = 5 * 1024 * 1024; // 5MB in bytes
    if ($file['size'] > $max_size) {
        wp_die('File too large. Maximum size: 5MB');
    }
    
    // Use WordPress file handling with security options
    $upload = wp_handle_upload($file, array(
        'test_form' => false,
        'mimes' => array(
            'jpg|jpeg' => 'image/jpeg',
            'png' => 'image/png',
            'gif' => 'image/gif'
        )
    ));
    
    if (isset($upload['error'])) {
        wp_die('Upload failed: ' . $upload['error']);
    }
    
    return $upload['url'];
}

XSS Prevention

php
/**
 * Comprehensive XSS prevention techniques
 * 
 * This function demonstrates multiple XSS prevention strategies:
 * - Input sanitization
 * - Output escaping
 * - Content Security Policy considerations
 * - Safe JSON output
 * 
 * @see https://owasp.org/www-project-cheat-sheets/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html
 * @see https://developer.wordpress.org/plugins/security/securing-output/
 */
function prevent_xss_attack() {
    // Never trust user input - always sanitize
    $user_input = $_POST['user_input'];
    
    // Always escape output for HTML context
    echo '<div>' . esc_html($user_input) . '</div>';
    
    // For rich content, use wp_kses with allowed HTML tags
    $allowed_html = array(
        'p' => array(),
        'br' => array(),
        'strong' => array(),
        'em' => array(),
        'a' => array(
            'href' => array(),
            'title' => array(),
            'target' => array()
        ),
        'ul' => array(),
        'ol' => array(),
        'li' => array()
    );
    
    echo wp_kses($user_input, $allowed_html);
    
    // For JSON output, ensure proper content type and escaping
    header('Content-Type: application/json');
    echo json_encode(array(
        'data' => esc_html($user_input),
        'timestamp' => current_time('timestamp')
    ));
    
    // Set Content Security Policy header
    header("Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline'");
}

📋 Security Checklist

Before Deployment

Ongoing Security

  • Regular security audits using Wordfence or Sucuri
  • WordPress core and plugins updated regularly
  • Security monitoring enabled with Query Monitor
  • Backup strategy implemented with UpdraftPlus
  • Incident response plan ready
  • Security training for team members

🔍 Security Testing

Manual Testing

  • Input Validation: Test with malicious inputs like <script>alert('XSS')</script>
  • XSS Testing: Try script injection in forms and URL parameters
  • CSRF Testing: Test form submissions without nonces
  • Privilege Escalation: Test with different user roles and capabilities

Automated Testing

php
/**
 * Security test function for automated testing
 * 
 * This function helps identify security vulnerabilities:
 * - Tests XSS prevention mechanisms
 * - Validates SQL injection protection
 * - Checks input sanitization
 * - Logs security test results
 * 
 * @see https://owasp.org/www-project-cheat-sheets/
 * @see https://developer.wordpress.org/plugins/security/
 */
function test_security_functions() {
    // Test XSS prevention
    $malicious_input = '<script>alert("XSS")</script>';
    $escaped_output = esc_html($malicious_input);
    
    if (strpos($escaped_output, '<script>') !== false) {
        error_log('XSS prevention failed: Script tags not escaped');
        return false;
    }
    
    // Test SQL injection prevention
    $malicious_sql = "'; DROP TABLE wp_posts; --";
    $sanitized_sql = sanitize_text_field($malicious_sql);
    
    if (strpos($sanitized_sql, 'DROP TABLE') !== false) {
        error_log('SQL injection prevention failed: Dangerous SQL not sanitized');
        return false;
    }
    
    // Test nonce verification
    if (wp_verify_nonce('invalid_nonce', 'test_action')) {
        error_log('Nonce verification failed: Invalid nonce accepted');
        return false;
    }
    
    error_log('Security tests passed successfully');
    return true;
}

🛠️ Security Tools

WordPress Security Plugins

Development Tools


💡 Tip: Security is not a one-time task but an ongoing process. Regularly review and update your security measures, stay informed about new vulnerabilities, and test your applications regularly. For more information, visit the WordPress Security Handbook, OWASP Top Ten, and WordPress Security Best Practices.