All security measures below are MANDATORY in every component (core, WordPress plugin, adapters). Based on MCP Official Best Practices 2026 + OWASP Top 10.
- HTTPS only — All MCP endpoints MUST be served over HTTPS
- No HTTP fallback — Reject plain HTTP requests to MCP endpoints
- TLS 1.2+ minimum
- Default: 100 requests/minute per IP
- Configurable via
security.rateLimitin config - Burst protection: 10 requests/second max burst
- Return
429 Too Many RequestswithRetry-Afterheader - Implementation: sliding window counter (in-memory or Redis)
- ALL inputs validated with Zod schemas before processing
- JSON-RPC request body: validate
jsonrpc,method,params,id - Tool parameters: validate types, ranges, string lengths
- URI parameters: validate against allowed patterns
- Never trust client input — sanitize everything
- Default: no CORS (same-origin only)
- Configurable:
security.allowedOriginswhitelist - Never use
Access-Control-Allow-Origin: *in production - Validate
Originheader against whitelist
Block ALL requests to private/internal IP ranges:
10.0.0.0/8172.16.0.0/12192.168.0.0/16127.0.0.0/8(localhost)169.254.0.0/16(link-local)::1(IPv6 localhost)fc00::/7(IPv6 private)
This applies to:
- Sitemap fetching
- Content fetching
- Any URL the server follows
- NEVER expose private/draft/password-protected/trashed content
- Respect CMS permissions:
- WordPress: only
publishstatus, only public post types - Other CMS: equivalent published/public status
- WordPress: only
- Filter out pages in
excludePathsconfig - Never expose admin pages, login pages, or internal routes
- Optional API key via
X-MCP-Keyheader - Optional Bearer token via
Authorizationheader - Keys stored as environment variables, NEVER in config files
- Keys compared using timing-safe comparison (
crypto.timingSafeEqual)
- Validate
Hostheader matches expected hostname - Reject requests with mismatched
Host(DNS rebinding protection) - Validate
Originheader on POST requests
All responses MUST include:
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 0
Referrer-Policy: strict-origin-when-cross-origin
Content-Security-Policy: default-src 'none'
Cache-Control: no-store (for MCP responses)
- MCP endpoints MUST NOT follow redirects automatically
- If content source returns a redirect, validate the target URL before following
- Block redirects to private IP ranges (SSRF via redirect)
- Log: timestamp, method, IP (hashed), response status, response time
- NEVER log: request body content, API keys, user data, page content
- Anonymous analytics only: count of AI queries per day (no content, no IPs)
- Configurable: can be disabled entirely
- Never expose stack traces, file paths, or internal errors to clients
- Return generic JSON-RPC error messages:
-32700Parse error-32600Invalid Request-32601Method not found-32602Invalid params-32603Internal error
- Log detailed errors server-side only
- Use WordPress nonces for admin AJAX
- Sanitize with
sanitize_text_field(),esc_html(),esc_url() - Use
$wpdb->prepare()for any database queries - Check
current_user_can()for admin actions - Use
wp_verify_nonce()for form submissions - REST API: proper
permission_callbackon all routes
- Lock all dependency versions (
package-lock.json/composer.lock) - Run
npm audit/composer auditin CI - No dependencies with known CVEs
- Minimal dependency tree — prefer built-in Node/PHP APIs
- All packages published from CI only (GitHub Actions)
- Signed commits recommended
package.jsonfilesfield to control what gets published.npmignoreto exclude tests, docs, configs from published package