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