# Woo Security

> Implement WooCommerce security — nonces, capabilities, input sanitization, output escaping, data validation, PCI compliance considerations, and WordPress security best practices. Use when hardening a WooCommerce store or reviewing security posture.

- Skill: `majiayu000/woo-security` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add majiayu000/woo-security`
- Raw SKILL.md: https://api.skillmd.com/api/skills/majiayu000/woo-security/raw
- Safety review: pending (external: skill-scanner PASS, skillspector PASS)
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Security
- Author: majiayu000 (https://skillmd.com/u/majiayu000)
- Updated: 2026-09-09
- Page: https://skillmd.com/skills/majiayu000/woo-security

---


# WooCommerce Security

## Before writing code

**Fetch live docs**:
1. Web-search `site:developer.wordpress.org plugins security` for WordPress security handbook
2. Web-search `site:developer.woocommerce.com security best practices` for WooCommerce security
3. Web-search `wordpress security hardening latest` for current hardening guidance

## Nonces (CSRF Protection)

### How Nonces Work

WordPress nonces prevent Cross-Site Request Forgery:
- Generate: `wp_create_nonce( 'my_action' )` or `wp_nonce_field( 'my_action', 'my_nonce' )` (for forms)
- Verify: `wp_verify_nonce( $_POST['my_nonce'], 'my_action' )` or `check_admin_referer( 'my_action', 'my_nonce' )`
- Valid for 24 hours (two 12-hour ticks)

### AJAX Nonces

- Generate: `wp_create_nonce( 'my_ajax_action' )`
- Pass to JS via `wp_localize_script()`: `['nonce' => wp_create_nonce('my_ajax_action')]`
- Verify in handler: `check_ajax_referer( 'my_ajax_action', 'nonce' )`

### REST API Nonces

- Cookie auth uses `X-WP-Nonce` header with `wp_create_nonce( 'wp_rest' )`
- API key auth doesn't need nonces (keys provide authentication)

## Capabilities (Authorization)

### WordPress Capability System

Always check capabilities before performing actions:
- `current_user_can( 'manage_woocommerce' )` — WooCommerce admin
- `current_user_can( 'edit_shop_orders' )` — order management
- `current_user_can( 'edit_products' )` — product management
- `current_user_can( 'view_woocommerce_reports' )` — view reports

### WooCommerce Capabilities

| Capability | Access |
|------------|--------|
| `manage_woocommerce` | Full WooCommerce admin |
| `edit_products` | Create/edit products |
| `edit_shop_orders` | Manage orders |
| `view_woocommerce_reports` | View analytics/reports |
| `edit_shop_coupons` | Manage coupons |

### Custom Capabilities

Register custom capabilities via `add_cap()` on role objects during plugin activation.

## Input Sanitization

### Sanitization Functions

Always sanitize data before using or storing it:

| Function | Use For |
|----------|---------|
| `sanitize_text_field()` | Single-line text input |
| `sanitize_textarea_field()` | Multi-line text |
| `sanitize_email()` | Email addresses |
| `sanitize_url()` | URLs |
| `absint()` | Positive integers |
| `intval()` | Integers (any sign) |
| `floatval()` | Float numbers |
| `wp_kses()` | HTML with allowed tags |
| `wp_kses_post()` | HTML safe for post content |
| `wc_clean()` | WooCommerce string/array sanitizer |
| `wc_sanitize_textarea()` | WooCommerce textarea sanitizer |

### Array Sanitization

`wc_clean()` recursively sanitizes arrays — use for multi-value inputs.

### File Upload Validation

- Validate MIME type with `wp_check_filetype()`
- Use `wp_handle_upload()` for proper file upload processing
- Never trust file extensions — validate content

## Output Escaping

### Escaping Functions

Always escape data on output:

| Function | Context |
|----------|---------|
| `esc_html()` | Inside HTML tags |
| `esc_attr()` | HTML attribute values |
| `esc_url()` | URLs (href, src) |
| `esc_js()` | Inline JavaScript |
| `esc_textarea()` | Inside textarea elements |
| `wp_kses()` | HTML with specific allowed tags |
| `wp_kses_post()` | HTML safe for post content |

### Translation + Escaping

Combine translation with escaping:
- `esc_html__()` / `esc_html_e()` — escaped translated strings
- `esc_attr__()` / `esc_attr_e()` — escaped for attributes
- `wp_kses( sprintf(...), $allowed_html )` — formatted HTML

### The Rule

**Sanitize early (on input), escape late (on output).** Never trust any data from users, databases, or external APIs.

## Data Validation

### Validation Patterns

- Validate data type, format, and range before processing
- Use `is_email()`, `wp_http_validate_url()`, WordPress validators
- WooCommerce validators: `wc_format_decimal()`, `wc_is_valid_url()`
- Return errors via `WP_Error` or `wc_add_notice( $msg, 'error' )`

## SQL Injection Prevention

### Prepared Statements

Always use `$wpdb->prepare()` for custom queries:
- `$wpdb->prepare( "SELECT * FROM {$wpdb->prefix}my_table WHERE id = %d", $id )`
- Placeholders: `%d` (integer), `%s` (string), `%f` (float)
- Never concatenate user input into SQL strings

### Use CRUD/APIs Instead

Prefer WooCommerce CRUD and WordPress APIs over raw SQL:
- `wc_get_orders()`, `wc_get_products()` — safe query builders
- `$order->get_meta()`, `$product->get_price()` — safe data access

## PCI Compliance Considerations

- **Never** store raw credit card numbers
- Use tokenized payment methods (Stripe, Braintree SDKs handle card data client-side)
- Serve checkout over HTTPS
- Keep WordPress, WooCommerce, and all plugins up to date
- Use payment gateways that are PCI DSS compliant

## Additional Hardening

- Set `DISALLOW_FILE_EDIT` in wp-config.php
- Limit login attempts (plugin or `.htaccess`)
- Use strong admin passwords and enforce password policies
- Enable two-factor authentication for admin users
- Keep all software updated (WordPress, WooCommerce, plugins, PHP)
- Use HTTPS everywhere
- Set secure cookie flags
- Restrict REST API access where appropriate (`rest_authentication_errors` filter)
- Disable XML-RPC if not needed: `add_filter( 'xmlrpc_enabled', '__return_false' )`

## Best Practices

- Check nonces on every form submission and AJAX request
- Check capabilities before every privileged operation
- Sanitize ALL input — even from trusted sources
- Escape ALL output — even data from the database
- Use `$wpdb->prepare()` for any custom SQL
- Never store sensitive data in plain text
- Use WordPress APIs instead of raw PHP functions for security-sensitive operations
- Run security audits with WPScan or similar tools

Fetch the WordPress Security handbook and WooCommerce security documentation for exact function signatures, capability mappings, and current best practices before implementing.

