| name | Security Hardening |
| description | This skill activates when users discuss WordPress security, OWASP vulnerabilities, CSP headers, XSS prevention, SQL injection, or security hardening. Provides guidance on securing WordPress themes and applications following OWASP Top 10 best practices. |
WordPress Security Hardening
Secure WordPress themes and applications against OWASP Top 10 vulnerabilities.
When This Activates
- "security", "hardening", "vulnerabilities", "OWASP"
- "XSS", "SQL injection", "CSRF", "CSP headers"
- "sanitize", "escape", "nonce verification"
- User asks about WordPress security
- Discussing security best practices
OWASP Top 10 for WordPress
1. Injection (SQL, XSS)
SQL Injection Prevention:
global $wpdb;
$user_id = $_GET['user_id'];
$results = $wpdb->get_results("SELECT * FROM users WHERE id = $user_id");
global $wpdb;
$user_id = intval($_GET['user_id']);
$results = $wpdb->get_results($wpdb->prepare(
"SELECT * FROM {$wpdb->users} WHERE id = %d",
$user_id
));
XSS Prevention:
echo esc_html($user_input);
echo esc_attr($user_input);
echo esc_url($user_input);
echo esc_js($user_input);
echo wp_kses_post($user_input);
echo sanitize_text_field($user_input);
<h1><?php echo esc_html(get_the_title()); ?></h1>
<a href="<?php echo esc_url(get_permalink()); ?>">
<?php echo esc_html(get_the_title()); ?>
</a>
<div data-product="<?php echo esc_attr($product_data); ?>"></div>
2. Broken Authentication
Nonce Verification:
wp_nonce_field('skyyrose_save_product', 'skyyrose_nonce');
if (!isset($_POST['skyyrose_nonce']) ||
!wp_verify_nonce($_POST['skyyrose_nonce'], 'skyyrose_save_product')
) {
wp_die('Security check failed');
}
wp_localize_script('skyyrose-app', 'skyyRose', [
'ajax_url' => admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('skyyrose_ajax'),
]);
function skyyrose_ajax_handler() {
check_ajax_referer('skyyrose_ajax', 'nonce');
}
add_action('wp_ajax_skyyrose_action', 'skyyrose_ajax_handler');
Capability Checks:
if (!current_user_can('edit_posts')) {
wp_die('Insufficient permissions');
}
if (!current_user_can('edit_product', $product_id)) {
wp_die('You cannot edit this product');
}
3. Sensitive Data Exposure
Don't Store Sensitive Data in Meta:
update_post_meta($order_id, '_credit_card', $_POST['card_number']);
function skyyrose_encrypt($data) {
$key = defined('SKYYROSE_ENCRYPTION_KEY') ? SKYYROSE_ENCRYPTION_KEY : '';
return openssl_encrypt($data, 'AES-256-CBC', $key);
}
Secure wp-config.php:
define('DISALLOW_FILE_EDIT', true);
define('FORCE_SSL_ADMIN', true);
$table_prefix = 'skyy_';
define('AUTH_KEY', 'put your unique phrase here');
4. XML External Entities (XXE)
Disable XML external entity processing:
add_filter('wp_check_filetype_and_ext', function($data, $file, $filename, $mimes) {
$filetype = wp_check_filetype($filename, $mimes);
if ($filetype['ext'] === 'xml') {
$data['ext'] = false;
$data['type'] = false;
}
return $data;
}, 10, 4);
5. Broken Access Control
Check User Permissions:
function skyyrose_save_product_meta($post_id) {
if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) return;
if (!isset($_POST['skyyrose_nonce']) ||
!wp_verify_nonce($_POST['skyyrose_nonce'], 'skyyrose_save_product')
) {
return;
}
if (!current_user_can('edit_post', $post_id)) {
return;
}
$collection = sanitize_text_field($_POST['skyyrose_collection']);
update_post_meta($post_id, '_skyyrose_collection', $collection);
}
add_action('save_post_product', 'skyyrose_save_product_meta');
REST API Permissions:
register_rest_route('skyyrose/v1', '/products/(?P<id>\d+)', [
'methods' => 'PUT',
'callback' => 'skyyrose_update_product',
'permission_callback' => function($request) {
return current_user_can('edit_products');
},
]);
6. Security Misconfiguration
Hide WordPress Version:
remove_action('wp_head', 'wp_generator');
add_filter('the_generator', '__return_empty_string');
function skyyrose_remove_version($src) {
return remove_query_arg('ver', $src);
}
add_filter('style_loader_src', 'skyyrose_remove_version', 9999);
add_filter('script_loader_src', 'skyyrose_remove_version', 9999);
Disable Directory Browsing:
# .htaccess
Options -Indexes
# Protect sensitive files
<FilesMatch "^(wp-config\.php|\.htaccess|php\.ini|readme\.html)">
Order allow,deny
Deny from all
</FilesMatch>
7. Cross-Site Scripting (XSS)
Always Escape Output:
<div class="product-card">
<h3><?php echo esc_html($product->name); ?></h3>
<p><?php echo esc_html($product->description); ?></p>
<a href="<?php echo esc_url($product->url); ?>">
View Product
</a>
</div>
// In JavaScript
<script>
const productName = <?php echo wp_json_encode($product->name); ?>;
</script>
Content Security Policy (CSP):
function skyyrose_set_csp_headers() {
if (is_admin()) return;
$csp = [
"default-src 'self'",
"script-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net https://cdn.babylonjs.com https://stats.wp.com",
"style-src 'self' 'unsafe-inline' https://fonts.googleapis.com https://fonts-api.wp.com",
"font-src 'self' data: https://fonts.gstatic.com https://fonts-api.wp.com",
"img-src 'self' data: https: blob:",
"connect-src 'self' https://stats.wp.com",
"frame-src 'self' https://widgets.wp.com",
"object-src 'none'",
"base-uri 'self'",
"form-action 'self'",
"upgrade-insecure-requests",
];
header('Content-Security-Policy: ' . implode('; ', $csp));
}
add_action('send_headers', 'skyyrose_set_csp_headers');
8. Insecure Deserialization
Avoid unserialize() with User Data:
$data = unserialize($_POST['data']);
$data = json_decode($_POST['data'], true);
$data = maybe_unserialize($trusted_data);
9. Using Components with Known Vulnerabilities
Keep WordPress Updated:
add_filter('auto_update_core', '__return_true');
add_filter('auto_update_plugin', '__return_true');
add_filter('auto_update_theme', '__return_true');
if (defined('WP_ENVIRONMENT_TYPE') && WP_ENVIRONMENT_TYPE !== 'production') {
}
Scan for Vulnerable Plugins:
wpscan --url https://skyyrose.co --api-token YOUR_TOKEN
10. Insufficient Logging & Monitoring
Security Event Logging:
function skyyrose_log_security_event($event_type, $details) {
$log_entry = [
'timestamp' => current_time('mysql'),
'event_type' => $event_type,
'user_id' => get_current_user_id(),
'ip' => $_SERVER['REMOTE_ADDR'],
'details' => $details,
];
error_log('[SECURITY] ' . wp_json_encode($log_entry));
}
add_action('wp_login_failed', function($username) {
skyyrose_log_security_event('login_failed', [
'username' => sanitize_user($username),
]);
});
add_action('wp_login', function($user_login, $user) {
if (user_can($user, 'manage_options')) {
skyyrose_log_security_event('admin_login', [
'username' => $user_login,
]);
}
}, , );
Additional Security Headers
function skyyrose_security_headers() {
header('X-Frame-Options: SAMEORIGIN');
header('X-Content-Type-Options: nosniff');
header('X-XSS-Protection: 1; mode=block');
header('Referrer-Policy: strict-origin-when-cross-origin');
header('Permissions-Policy: geolocation=(), microphone=(), camera=()');
}
add_action('send_headers', 'skyyrose_security_headers');
Input Validation & Sanitization
function skyyrose_validate_product_input($data) {
$validated = [];
if (empty($data['name'])) {
return new WP_Error('missing_name', 'Product name is required');
}
$validated['name'] = sanitize_text_field($data['name']);
if (!empty($data['email'])) {
$email = sanitize_email($data['email']);
if (!is_email($email)) {
return new WP_Error('invalid_email', 'Invalid email address');
}
$validated['email'] = $email;
}
if (!empty($data['url'])) {
$url = esc_url_raw($data['url']);
(!(, FILTER_VALIDATE_URL)) {
(, );
}
[] = ;
}
(([])) {
[] = ([]);
}
(([])) {
[] = ([]);
}
= [, , ];
(([])) {
(!([], , )) {
(, );
}
[] = [];
}
;
}
File Upload Security
function skyyrose_secure_file_upload($file) {
if ($file['size'] > 5 * 1024 * 1024) {
return new WP_Error('file_too_large', 'File must be under 5MB');
}
$allowed_types = ['image/jpeg', 'image/png', 'image/webp'];
$filetype = wp_check_filetype($file['name'], $allowed_types);
if (!in_array($filetype['type'], $allowed_types, true)) {
return new WP_Error('invalid_file_type', 'Only JPEG, PNG, WebP allowed');
}
if (!getimagesize($file['tmp_name'])) {
return new WP_Error('not_an_image', 'File is not a valid image');
}
$filename = ([]);
[] = ;
(, function() {
[] = [] . ;
[] = [] . ;
;
});
= (, [ => ]);
(([])) {
(, []);
}
;
}
Database Security
global $wpdb;
$user_id = 123;
$wpdb->get_var($wpdb->prepare(
"SELECT meta_value FROM {$wpdb->usermeta} WHERE user_id = %d AND meta_key = %s",
$user_id,
'skyyrose_preference'
));
$collection_ids = [1, 2, 3];
$placeholders = implode(',', array_fill(0, count($collection_ids), '%d'));
$wpdb->get_results($wpdb->prepare(
"SELECT * FROM {$wpdb->posts} WHERE ID IN ($placeholders)",
...$collection_ids
));
$search = $wpdb->esc_like($_GET['search']) . '%';
$wpdb->get_results($wpdb->prepare(
"SELECT * FROM {$wpdb->posts} WHERE post_title LIKE %s",
$search
));
Authentication & Authorization
function skyyrose_check_login_attempts($user, $username, $password) {
$max_attempts = 5;
$lockout_duration = 15 * MINUTE_IN_SECONDS;
$transient_key = 'login_attempts_' . md5($username);
$attempts = get_transient($transient_key);
if ($attempts >= $max_attempts) {
return new WP_Error(
'too_many_attempts',
'Too many login attempts. Try again in 15 minutes.'
);
}
return $user;
}
add_filter('authenticate', 'skyyrose_check_login_attempts', 30, 3);
add_action('wp_login_failed', function($username) {
$transient_key = 'login_attempts_' . md5($username);
$attempts = get_transient($transient_key) ?: ;
(, + , * MINUTE_IN_SECONDS);
});
Security Checklist for SkyyRose
Security Plugins Recommended
- Wordfence Security: Firewall, malware scanning, 2FA
- Sucuri Security: Security auditing, monitoring
- iThemes Security: Hardening, brute force protection
- Limit Login Attempts Reloaded: Prevent brute force
When User Asks About Security
- Assess current state: Run security scan (Wordfence, WPScan)
- Identify vulnerabilities: Check OWASP Top 10
- Prioritize fixes: Critical → High → Medium → Low
- Implement hardening: Input validation, output escaping, headers
- Monitor: Set up logging, alerts, regular scans
Always follow defense in depth: multiple layers of security.