Clickjacking Prevention in WordPress
Clickjacking is a deceptive UI attack where your website is loaded inside a hidden or transparent <iframe>
, tricking users into clicking buttons they never meant to. Effective Clickjacking Prevention in WordPress involves sending the correct HTTP security headers, testing them thoroughly, and allowing only the embeds you truly need. In this guide, you’ll get practical, copy-paste code for Apache, Nginx, and WordPress, plus testing steps and troubleshooting tips.
Why Clickjacking Prevention in WordPress Matters
Attackers can overlay your site within their page and invisibly funnel clicks to sensitive actions (e.g., “Delete account,” “Change email,” “Submit payment”). If your site allows framing by default, you’re at risk. Clickjacking Prevention in WordPress relies primarily on:
X-Frame-Options
(legacy but still widely respected):DENY
,SAMEORIGIN
, orALLOW-FROM
(discouraged—poor support).Content-Security-Policy: frame-ancestors …
: modern, flexible control over which origins may embed your site.
Best practice: Use CSP frame-ancestors
and keep X-Frame-Options
as a compatible backup.
Quick Wins for Clickjacking Prevention in WordPress
- Send both
X-Frame-Options: SAMEORIGIN
andContent-Security-Policy: frame-ancestors 'self'
. - If you must allow specific partner domains, allowlist them with
frame-ancestors
. - Test with a minimal attacker page (below) to confirm your headers block framing.
- Apply these headers to every route, including
/wp-admin/
and sensitive front-end forms.
Apache (.htaccess) Configuration
Add to your WordPress site’s .htaccess
(in the web root):
# Clickjacking Prevention in WordPress via Apache (.htaccess)
<IfModule mod_headers.c>
# Legacy header for broad support
Header always set X-Frame-Options "SAMEORIGIN"
# Modern, flexible control (adjust allowlist as needed)
Header always set Content-Security-Policy "frame-ancestors 'self';"
</IfModule>
Allowlisting a Trusted Domain (e.g., your support portal)
<IfModule mod_headers.c>
Header always set X-Frame-Options "SAMEORIGIN"
Header always set Content-Security-Policy "frame-ancestors 'self' https://support.example.com;"
</IfModule>
Note: If you use an iframe-based widget (chat, booking), add its exact origin to
frame-ancestors
.
Screenshot of our Free Website Vulnerability Scanner homepage
Nginx Configuration
In your site’s server block:
# Clickjacking Prevention in WordPress via Nginx
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Content-Security-Policy "frame-ancestors 'self';" always;
Allowlist a partner domain:
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Content-Security-Policy "frame-ancestors 'self' https://support.example.com;" always;
Reload Nginx after changes:
sudo nginx -t && sudo systemctl reload nginx
WordPress-Only Approach (No Server Access)
If you can’t touch the web server, enforce Clickjacking Prevention in WordPress via PHP. Use the send_headers
hook in functions.php
or a small must-use plugin.
functions.php (theme-level)
// Clickjacking Prevention in WordPress via functions.php
add_action('send_headers', function () {
header("X-Frame-Options: SAMEORIGIN");
header("Content-Security-Policy: frame-ancestors 'self';");
});
Safer: A Tiny MU-Plugin (survives theme changes)
Create /wp-content/mu-plugins/security-headers.php
:
<?php
/**
* Plugin Name: Security Headers - Clickjacking Protection
* Description: Adds X-Frame-Options and CSP frame-ancestors for Clickjacking Prevention in WordPress.
*/
add_action('send_headers', function () {
// Adjust allowlist as required
header("X-Frame-Options: SAMEORIGIN");
header("Content-Security-Policy: frame-ancestors 'self';");
});
Allowlist (When You Must Embed on a Known Domain)
add_action('send_headers', function () {
header("X-Frame-Options: SAMEORIGIN");
header("Content-Security-Policy: frame-ancestors 'self' https://support.example.com https://partner.cdn.example;");
});
Testing: Prove Your Headers Work
- Create a simple attacker page on a separate domain (or local file):
<!-- attacker.html -->
<!doctype html>
<title>Test Clickjacking</title>
<style>iframe { width: 100vw; height: 100vh; opacity: 0.01; }</style>
<iframe src="https://your-site.example/"></iframe>
- Open
attacker.html
in a browser.- If framing is blocked, you’ll see nothing or a console error.
- Check DevTools Network → Response Headers for
X-Frame-Options
andContent-Security-Policy
.
- CLI check:
curl -s -I https://your-site.example/ | egrep -i "x-frame-options|content-security-policy"
Sample assessment report by our free tool to check Website Vulnerability
Granular Control: Only Allow Framing on a Specific Page
Some flows (e.g., checkout embedded in a partner app) may require framing only on one URL.
Apache per-location (WordPress pretty permalinks):
<IfModule mod_headers.c>
# Default deny framing everywhere
Header always set X-Frame-Options "SAMEORIGIN"
Header always set Content-Security-Policy "frame-ancestors 'self';"
# Allow framing for a specific path
<LocationMatch "^/embed/checkout/?$">
Header always set Content-Security-Policy "frame-ancestors 'self' https://partner.example;"
</LocationMatch>
</IfModule>
Nginx per-location:
# Default policy
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Content-Security-Policy "frame-ancestors 'self';" always;
# For a specific route:
location = /embed/checkout {
add_header Content-Security-Policy "frame-ancestors 'self' https://partner.example;" always;
}
WordPress conditional (PHP):
add_action('send_headers', function () {
$csp = "frame-ancestors 'self';";
if (isset($_SERVER['REQUEST_URI']) && preg_match('#^/embed/checkout/?$#', $_SERVER['REQUEST_URI'])) {
$csp = "frame-ancestors 'self' https://partner.example;";
}
header("X-Frame-Options: SAMEORIGIN");
header("Content-Security-Policy: {$csp}");
});
Multisite Notes (WordPress Network)
On multisite, keep Clickjacking Prevention in WordPress consistent via a network-activated MU-plugin. If one child site must be embeddable, add a per-site allowlist:
add_action('send_headers', function () {
$allow = ["'self'"];
// Example: allow framing only for site with blog_id 5
if (function_exists('get_current_blog_id') && get_current_blog_id() === 5) {
$allow[] = "https://partner.example";
}
header("X-Frame-Options: SAMEORIGIN");
header("Content-Security-Policy: frame-ancestors " . implode(' ', $allow) . ";");
});
Legacy “Frame-Busting” JavaScript (Use Only as a Supplement)
JS solutions like the following are not reliable (headers win), but you may add them as an extra belt:
<script>
if (top !== self) {
// Replace the framing page with your page
top.location = self.location;
}
</script>
Headers are mandatory; treat JS as supplementary only.
Troubleshooting: When Embeds Break
- Your site needs to be embedded in your own app? Use
frame-ancestors 'self' https://app.yourbrand.com;
. - Third-party widgets stopped working? Check their embed domain and add it to
frame-ancestors
. Many vendors use distinct CDN origins. - CSP errors in console? Tune
frame-ancestors
precisely; don’t confuse it withframe-src
(older directive). - CDN in front (Cloudflare, etc.)? Verify headers are not being overwritten at the edge.
For ongoing assurance, run scans with your free tool: https://free.pentesttesting.com/.
Related Reading (Internal Links)
- Deep dive on broken auth flows: Broken Authentication in Node.js
- File upload hardening: Unrestricted File Upload in WordPress
- Access control defenses: Fix IDOR Vulnerability in WordPress
- Framework injection protection: Preventing SQL Injection (SQLi) in Symfony
These posts complement Clickjacking Prevention in WordPress by addressing adjacent risks attackers often chain together.
New & Popular Services (How We Can Help)
Managed IT Services for Secure, Smooth Operations
If you want consistent patching, monitoring, and response without hiring a full team, explore Managed IT Services. We’ll keep security headers, TLS, and WordPress updates locked in—so Clickjacking Prevention in WordPress stays intact.
AI Application Cybersecurity (Models, APIs, & Plugins)
Building with AI? See AI Application Cybersecurity. We threat-model prompts, secure AI plugins, and apply CSP/headers on AI-driven UIs—Clickjacking Prevention in WordPress included where your WP site fronts an AI workflow.
Offer Cybersecurity to Your Clients (Partner/White-Label)
Agencies and MSPs: Offer Cybersecurity Service to Your Client with our white-label pentesting and hardening kits. We help you deliver Clickjacking Prevention in WordPress at scale.
Copy-Paste Recipes (Mini Cookbook)
Block all framing everywhere (strict):
X-Frame-Options: DENY
Content-Security-Policy: frame-ancestors 'none';
Allow your own domain only (typical WordPress):
X-Frame-Options: SAMEORIGIN
Content-Security-Policy: frame-ancestors 'self';
Allow your brand + a partner:
X-Frame-Options: SAMEORIGIN
Content-Security-Policy: frame-ancestors 'self' https://partner.example;
Test quickly with cURL (spot-check):
curl -I https://your-site.example/ | egrep -i "x-frame-options|content-security-policy"
Final Takeaways
- Default-deny with
frame-ancestors 'self'
(andX-Frame-Options: SAMEORIGIN
as a backup). - Add precision allowlists only where business requires embedding.
- Re-test headers every deployment; automate checks via CI or scheduled scans.
- Use our free scanner for Website Security check before/after changes to validate Clickjacking Prevention in WordPress continuously.
🔐 Frequently Asked Questions (FAQs)
Find answers to commonly asked questions about Clickjacking Prevention in WordPress.