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
- Defense in Depth: Multiple layers of security protection following OWASP security principles
- Principle of Least Privilege: Grant minimum necessary permissions using WordPress user roles
- Input Validation: Validate all user inputs using WordPress sanitization functions
- Output Escaping: Escape all outputs for display using WordPress escaping functions
- Nonce Verification: Protect against CSRF attacks using WordPress nonces
Common Vulnerabilities
- Cross-Site Scripting (XSS): Malicious scripts injected into pages - OWASP XSS Prevention
- SQL Injection: Malicious SQL code in database queries - OWASP SQL Injection Prevention
- Cross-Site Request Forgery (CSRF): Unauthorized actions on behalf of users - OWASP CSRF Prevention
- Privilege Escalation: Unauthorized access to higher privileges
- File Upload Vulnerabilities: Malicious file uploads - OWASP File Upload Cheat Sheet
🔧 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
- All user inputs sanitized using WordPress sanitization functions
- All outputs escaped using WordPress escaping functions
- Nonce verification implemented for all forms and AJAX requests
- Capability checks in place using current_user_can()
- File uploads secured with proper validation and wp_handle_upload()
- SQL queries use prepared statements with $wpdb->prepare()
- REST API endpoints secured with proper permission callbacks
- Error messages don't leak sensitive information
- HTTPS enforced using force_ssl_admin()
- Security headers configured using security headers
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
- Wordfence: Comprehensive security suite with firewall and malware scanning
- Sucuri: Security monitoring and malware scanning
- iThemes Security: Security hardening and monitoring
- All In One WP Security: Security features and monitoring
Development Tools
- PHP Security Checker: Scan for known vulnerabilities in PHP dependencies
- OWASP ZAP: Web application security testing tool
- Burp Suite: Web application security testing platform
- Nikto: Web server security scanner
💡 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.