wordpress-security-validation
Security-first WordPress development with nonces, sanitization, validation, and escaping to prevent XSS, CSRF, and SQL injection vulnerabilities.
By bobmatnyc · 484 installs
npx skills add bobmatnyc/claude-mpm-skills --skill wordpress-security-validation
Source repository · Upstream listing
WordPress Security & Data Validation
Version: 1.1.0
Target: WordPress 6.7+ PHP 8.3+
Skill Level: Intermediate to Advanced
Overview
Security is not optional in WordPress development—it's fundamental. This skill teaches the three layer security model that prevents XSS, CSRF, SQL injection, and other common web vulnerabilities through proper input sanitization, business logic validation, and output escaping.
The Golden Rule: "Sanitize on input, validate for logic, escape on output."
Why This Matters
Every year, thousands of WordPress sites are compromised due to security vulnerabilities in plugins and themes. Most of these attacks exploit one of three weaknesses:
1. XSS (Cross Site Scripting): Malicious JavaScript injected through unsanitized output
2. CSRF (Cross Site Request Forgery): Unauthorized actions performed on behalf of authenticated users
3. SQL Injection: Database manipulation through unsanitized database queries
This skill provides complete, production ready patterns for preventing all three attack vectors.
The Three Layer Security Model
WordPress security follows a defense in depth strategy with three distinct layers:
Layer 1: Sanitization (Input Cleaning)
Purpose: Remove dangerous characters and normalize data format
When: Immediately upon receiving user input
Example: sanitize text field($ POST['username'])
Layer 2: Validation (Logic Checks)
Purpose: Ensure data meets business requirements
When: After sanitization, before processing
Example: if (!is email($email)) { / error / }
Layer 3: Escaping (Output Protection)
Purpose: Prevent XSS by encoding special characters
When: Every time you output data to browser
Example: echo esc html($user input);
Critical Distinction:
Sanitization removes/transforms invalid data (changes the value)
Validation checks if data is acceptable (returns true/false)
Escaping makes data safe for display (context specific encoding)
1. Nonces: CSRF Protection
What Are Nonces?
Nonces (Numbers Used Once) are cryptographic tokens that verify a request originated from your site, not a malicious external source. They prevent Cross Site Request Forgery (CSRF) attacks.
How CSRF Attacks Work:
How Nonces Prevent CSRF:
Nonce Implementation Patterns
Pattern 1: Form Nonces (Most Common)
BEFORE (Vulnerable):
AFTER (Secure):
Key Functions:
wp nonce field($action, $name) Generates hidden nonce field
wp verify nonce($nonce, $action) Verifies nonce validity
Pattern 2: URL Nonces
Use Case: Delete/trash links, admin actions
Pattern 3: AJAX Nonces
Use Case: Frontend AJAX requests
BEFORE (Vulnerable):
AFTER (Secure):
PHP (Enqueue script with nonce):
JavaScript (Use nonce in AJAX):
Key Functions:
wp create nonce($action) Generate nonce token
check ajax referer($action, $query arg) Verify AJAX nonce (dies on failure)
wp send json success($data) Send JSON success response
wp send json error($data) Send JSON error response
Nonce Best Practices
✅ DO:
Use unique action names (e.g., delete post $post id , not just delete )
Always verify nonces BEFORE processing any data
Combine nonce checks with capability checks
Use specific nonce functions ( check ajax referer for AJAX)
❌ DON'T:
Reuse the same nonce action for multiple operations
Skip nonce verification for "read only" operations
Trust nonce verification alone (always check capabilities too)
Store nonces in cookies or URLs for long term use (they expire)
Nonce Lifespan: WordPress nonces expire after 24 hours by default (12 hours in each direction due to time window).
2. Sanitization Functions Reference
Sanitization transforms user input into a safe format by removing or encoding dangerous characters. It's the first line of defense against malicious data.
Core Sanitization Functions
Function Use Case Example Input Output
sanitize text field() Single line text (usernames, titles) "Hello <script alert('xss')</script " "Hello alert('xss')"
sanitize email() Email addresses "user@example.com<script " "user@example.com"
sanitize url() / esc url raw() URLs (for storage) "javascript:alert('xss')" "" (blocked)
sanitize key() Array keys, meta keys "my key!" "my key"
sanitize file name() File uploads "../../etc/passwd" "..etcpasswd"
absint() Positive integers " 5" , "42abc" 5 , 42
intval() Any integer " 5" , "42.7" 5 , 42
floatval() Floating point numbers "3.14abc" 3.14
wp kses post() HTML content (allows safe tags) "<p Safe</p <script Bad</script " "<p Safe</p "
wp kses() HTML with custom allowed tags See below Custom filtering
sanitize textarea field() Multi line text "Line 1\nLine 2<script " "Line 1\nLine 2"
sanitize title() Post slugs "Hello World!" "hello world"
Detailed Examples
Text Sanitization
Numeric Sanitization
HTML Sanitization
wp kses post() Allow WordPress Post Editor Tags:
wp kses() Custom Allowed Tags:
Strip All HTML:
File Upload Sanitization
Array Sanitization
Custom Sanitization Callbacks
3. Validation Patterns
Validation ensures data meets business logic requirements after sanitization. Unlike sanitization (which transforms data), validation returns true/false .
Built in Validation Functions
Function Purpose Example
is email($email) Valid email format is email('user@example.com') → true
is numeric($value) Numeric string is numeric('42') → true
is int($value) Integer type is int(42) → true
is array($value) Array type is array([1,2,3]) → true
is user logged in() User authentication is user logged in() → true/false
username exists($user) Username exists username exists('admin') → user id or null
email exists($email) Email exists email exists('user@example.com') → user id or false
Validation Examples
Email Validation
Numeric Range Validation
String Length Validation
Required Field Validation
Pattern Matching (Regex)
Multi Field Validation
Custom Validation Rules
4. Output Escaping Reference
Escaping prevents XSS (Cross Site Scripting) by encoding special characters before output. This is the final security layer .
Core Escaping Functions
Function Context Escapes Example Use
esc html() HTML content < & " ' echo esc html($user input);
esc attr() HTML attributes < & " ' <input value="<?php echo esc attr($value); ? "
esc url() HTML href/src Dangerous protocols <a href="<?php echo esc url($link); ? "
esc js() JavaScript strings ' " \ / <script var msg = '<?php echo esc js($message); ? ';</script
esc sql() DEPRECATED (use $wpdb prepare() ) SQL special chars ❌ Don't use
esc textarea() Textarea content < & <textarea <?php echo esc textarea($content); ? </textarea
Detailed Escaping Examples
HTML Content Escaping
HTML Attribute Escaping
URL Escaping
JavaScript Escaping
Textarea Escaping
Context Specific Escaping
HTML Context
Attribute Context
JavaScript Context
Internationalization + Escaping
Common Escaping Mistakes
❌ WRONG:
✅ CORRECT:
5. Capability Checks (Authorization)
Capability checks ensure users have permission to perform actions. Always combine with nonce verification.
Built in Capabilities
Capability Description Default Roles
read View content All logged in users
edit posts Create/edit own posts Author, Editor, Admin
edit published posts Edit published posts Editor, Admin
delete posts Delete own posts Author, Editor, Admin
manage options Manage site settings Admin only
upload files Upload media Author, Editor, Admin
edit users Edit user accounts Admin only
delete users Delete users Admin only
install plugins Install/activate plugins Admin only
switch themes Change themes Admin only
Capability Check Patterns
Basic Capability Check
Complete Security Example
Post Specific Capabilities
Custom Capabilities
6. SQL Injection Prevention
CRITICAL: Never trust user input in SQL queries. Always use $wpdb prepare() .
The Problem: SQL Injection
BEFORE (Vulnerable):
AFTER (Secure):
Prepared Statement Placeholders
Placeholder Type Example
%s String "SELECT FROM table WHERE name = %s"
%d Integer "SELECT FROM table WHERE id = %d"
%f Float "SELECT FROM table WHERE price = %f"
Complete Examples
SELECT Query
INSERT Query
UPDATE Query
DELETE Query
Complex WHERE Clause
Common SQL Injection Mistakes
❌ WRONG:
✅ CORRECT:
7. Common Vulnerabilities & Attack Scenarios
XSS (Cross Site Scripting)
Attack Scenario:
Prevention:
CSRF (Cross Site Request Forgery)
Attack Scenario:
Prevention:
SQL Injection
Attack Scenario:
Prevention:
File Upload Attack
Attack Scenario:
Prevention:
Path Traversal
Attack Scenario:
Prevention:
8. Complete Security Implementation Example
9. Security Checklist
Use this checklist for every WordPress feature you implement:
Input Security (Forms, AJAX, APIs)
[ ] Nonce verification implemented ( wp verify nonce() )
[ ] Capability check performed ( current user can() )
[ ] All input sanitized with appropriate functions
[ ] All input validated for business logic
[ ] File uploads use wp handle upload()
[ ] File types whitelisted, not blacklisted
Output Security (Templates, APIs)
[ ] All dynamic content escaped with esc html() , esc attr() , etc.
[ ] URLs escaped with esc url()
[ ] JavaScript variables use wp localize script() or esc js()
[ ] No raw echo $ POST or echo $ GET
Database Security
[ ] All queries use $wpdb prepare()
[ ] No string concatenation in SQL
[ ] Use $wpdb insert() , $wpdb update() , $wpdb delete()
[ ] Table names use $wpdb prefix
Session Security
[ ] User authentication checked ( is user logged in() )
[ ] User roles validated ( current user can() )
[ ] Sensitive operations require re authentication
[ ] Session data never stored in GET parameters
Code Quality
[ ] No eval() , assert() , or create function()
[ ] No extract() on user input
[ ] Error messages don't reveal system information
[ ] Debug mode disabled in production ( WP DEBUG = false )
[ ] No phpinfo() / var dump() / print r() reachable in production (server info disclosure)
[ ] No empty catch blocks on security relevant operations — fail closed and log the cause
[ ] Every switch over user controlled or access control input has a fail closed default
Code quality defects with a security dimension: phpinfo() left in production
leaks server internals; empty catch blocks silently swallow failed signature or
capability checks (failing open ); a switch with no default lets unexpected input
fall through unhandled (CWE 478). See
[PHP Quality Anti Patterns](references/php quality antipatterns.md) for
compliant/non compliant examples. Patterns derived from CAST Highlight code quality
indicators (https://doc.casthighlight.com/).
10. Testing Your Security Implementation
Manual Testing Checklist
1. Test Nonce Expiration:
2. Test CSRF Protection:
3. Test XSS Prevention:
4. Test SQL Injection:
5. Test Capability Bypass:
Automated Security Testing
Install Security Sca