HIGH clickjackingstrapi

Clickjacking in Strapi

How Clickjacking Manifests in Strapi

Clickjacking in Strapi exploits the platform's rich admin interface and API endpoints to trick administrators into performing unintended actions. Strapi's dashboard, which runs on the same domain as your API, creates an ideal environment for clickjacking attacks when proper security headers aren't configured.

The most common Strapi-specific clickjacking scenario targets the admin dashboard. An attacker crafts a malicious page that loads Strapi's admin interface in an invisible iframe. The attacker then overlays deceptive UI elements—buttons, forms, or text—that appear to be part of the attacker's site but actually sit on top of the real Strapi admin interface. When an administrator clicks what appears to be a legitimate button on the malicious page, they're actually clicking buttons in the hidden Strapi dashboard.

Strapi's content management features are particularly vulnerable. The platform's rich text editor, file upload dialogs, and content creation forms can all be manipulated through clickjacking. For example, an attacker could create a page that makes an administrator unknowingly publish draft content, delete critical data, or modify user permissions while believing they're performing harmless actions on the attacker's site.

The authentication flow presents another attack vector. Strapi's JWT-based authentication and session management can be exploited if the admin interface isn't properly protected. An attacker might craft a page that triggers Strapi's login form in an iframe, then use timing attacks combined with social engineering to capture credentials or force authentication into an attacker-controlled session.

Strapi's plugin architecture adds complexity to clickjacking risks. Third-party plugins might introduce their own admin interfaces or API endpoints without proper frame-busting code. A plugin that creates custom content types with admin interfaces could become a clickjacking target if it doesn't implement the same security measures as core Strapi components.

The REST API endpoints themselves can be clickjacked in certain configurations. While Strapi's API is typically consumed by frontend applications rather than browsers directly, if your Strapi instance serves a frontend application or if API endpoints are accessed directly in browsers, they could be loaded in iframes and subjected to clickjacking attacks that manipulate form submissions or trigger state-changing operations.

Strapi's default configuration doesn't include clickjacking protections, making this a common oversight in Strapi deployments. The platform focuses on developer experience and rapid content management, but security headers and frame-busting measures must be added explicitly by developers or administrators.

Strapi-Specific Detection

Detecting clickjacking vulnerabilities in Strapi requires examining both your application's configuration and its runtime behavior. Start with the HTTP response headers from your Strapi instance—these are the first line of defense against clickjacking attacks.

Use curl or a browser's developer tools to check for critical security headers. A vulnerable Strapi instance will return responses without X-Frame-Options or Content-Security-Policy frame-ancestors directives. For example, a secure response should include headers like:

HTTP/1.1 200 OK
X-Frame-Options: DENY
Content-Security-Policy: frame-ancestors 'none'

Run automated scans using middleBrick to detect clickjacking vulnerabilities specifically in Strapi deployments. middleBrick's black-box scanning approach tests your Strapi instance by attempting to load admin interfaces and API endpoints in iframes, then analyzes the response headers and behavior to determine if clickjacking is possible.

middleBrick's Strapi-specific detection includes checking for:

  • Missing or weak X-Frame-Options headers on admin and API endpoints
  • Absence of Content-Security-Policy frame-ancestors directives
  • JavaScript-based frame-busting code that can be bypassed
  • Plugin admin interfaces that lack clickjacking protections
  • API endpoints that return sensitive data without proper framing restrictions
  • Authentication endpoints vulnerable to framing-based credential harvesting

Test your Strapi admin interface manually by attempting to load it in an iframe on a different domain. If the admin interface loads successfully without any frame-busting mechanisms or security headers, your Strapi instance is vulnerable to clickjacking.

Examine your Strapi plugins individually, as third-party plugins might introduce admin interfaces or API endpoints that bypass your main application's security measures. middleBrick's scanning can identify which specific endpoints and plugins are vulnerable, allowing you to prioritize remediation efforts.

Monitor for unusual admin activity patterns that might indicate clickjacking attacks in progress. While clickjacking itself doesn't leave server-side logs, correlating admin interface access patterns with unexpected content modifications or permission changes can help identify ongoing attacks.

Strapi-Specific Remediation

Securing Strapi against clickjacking requires implementing multiple defense layers. The most effective approach combines HTTP security headers with Strapi-specific configuration changes.

Start by adding clickjacking protections to your Strapi application's main server file. In your Strapi project's src/server.js or equivalent startup file, add middleware that sets security headers:

module.exports = ({ strapi }) => {
  return {
    initialize() {
      strapi.app.use(async (ctx, next) => {
        // Set X-Frame-Options for all responses
        ctx.set('X-Frame-Options', 'DENY');
        
        // Set Content-Security-Policy frame-ancestors
        ctx.set('Content-Security-Policy', "frame-ancestors 'none'");
        
        await next();
      });
    }
  };
};

For Strapi applications behind reverse proxies or load balancers, configure clickjacking protections at the proxy level. In your nginx configuration:

server {
    listen 80;
    server_name yourapi.com;
    
    # Clickjacking protection
    add_header X-Frame-Options DENY always;
    add_header Content-Security-Policy "frame-ancestors 'none'" always;
    
    # Other security headers
    add_header X-Content-Type-Options nosniff always;
    add_header X-XSS-Protection "1; mode=block" always;
    
    location / {
        proxy_pass http://localhost:1337;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

Implement plugin-specific protections for third-party Strapi plugins. Many plugins create their own admin interfaces or API endpoints that might bypass your main application's security measures. Create a plugin-level middleware in each plugin's src/index.js:

module.exports = strapi => {
  strapi.app.use(async (ctx, next) => {
    if (ctx.request.path.startsWith('/plugins/your-plugin')) {
      ctx.set('X-Frame-Options', 'DENY');
      ctx.set('Content-Security-Policy', "frame-ancestors 'none'");
    }
    await next();
  });
};

For Strapi applications that must support specific framing scenarios (like embedded dashboards), use more granular Content-Security-Policy directives instead of DENY. Allow framing only from specific trusted origins:

ctx.set('Content-Security-Policy', "frame-ancestors https://yourapp.com https://yourotherapp.com");

Implement JavaScript-based frame-busting as a defense-in-depth measure, though this should complement rather than replace HTTP header protections:

// In your admin interface entry point
if (top.location !== self.location) {
  top.location = self.location;
}

Configure Strapi's CORS settings to prevent clickjacking through cross-origin requests. In your config/server.js:

module.exports = () => {
  return {
    host: process.env.APP_HOST || 'localhost',
    port: process.env.PORT || 1337,
    cron: {
      enabled: true,
    },
    admin: {
      autoOpen: false,
      url: process.env.APP_URL + '/admin',
    },
    csp: {
      // Content Security Policy configuration
      directives: {
        'default-src': ["'self'"],
        'frame-ancestors': ["'none'"],
      },
    },
  };
};

Test your remediation by attempting to load your Strapi admin interface in an iframe after implementing these protections. A properly secured Strapi instance will either refuse to load in the iframe or redirect to the top-level window, preventing clickjacking attacks.

Frequently Asked Questions

Why doesn't Strapi include clickjacking protections by default?
Strapi prioritizes developer experience and flexibility, allowing developers to choose their own security configurations based on deployment scenarios. The framework doesn't assume a specific deployment architecture, so security headers must be added explicitly based on whether Strapi runs behind proxies, in containers, or as a standalone service.
Can clickjacking affect Strapi's API endpoints, not just the admin interface?
Yes, API endpoints can be clickjacked if they return sensitive data or allow state-changing operations without proper framing restrictions. This is particularly concerning for endpoints that modify content, user permissions, or system configuration. Always apply the same clickjacking protections to both admin and API endpoints.