MEDIUM clickjackinghapi

Clickjacking in Hapi

How Clickjacking Manifests in Hapi

Clickjacking in Hapi applications typically exploits missing or misconfigured security headers, particularly the X-Frame-Options and Content-Security-Policy (CSP) frame-ancestors directives. Since Hapi uses a plugin-based architecture, clickjacking vulnerabilities often emerge when developers overlook security configuration in route handlers or fail to implement global security policies.

The most common attack pattern involves malicious websites embedding Hapi application pages within iframes to trick users into performing unintended actions. For example, an attacker might create a page that overlays a transparent iframe of your Hapi application's admin interface, positioning it over a seemingly legitimate button. When users click what they believe is a normal button, they're actually interacting with your Hapi application's interface.

In Hapi, this vulnerability frequently appears in routes serving sensitive operations like:

server.route({
  method: 'POST',
  path: '/admin/delete-user',
  handler: async (request, h) => {
    // No security headers - vulnerable to clickjacking
    const userId = request.payload.userId;
    await deleteUser(userId);
    return { success: true };
  }
});

Without proper frame-busting or security headers, this route can be exploited regardless of whether the user is authenticated. The vulnerability is particularly dangerous when combined with Hapi's flexible response handling, as developers might return different response types (HTML, JSON, redirects) without consistent security header application.

Another Hapi-specific manifestation occurs with plugin conflicts. When using multiple plugins that modify response headers, security headers can be inadvertently overwritten or removed. For instance, a view rendering plugin might strip security headers added by an earlier security plugin, creating inconsistent protection across your application.

Clickjacking can also exploit Hapi's route-level configuration where developers apply security policies inconsistently. A common mistake is applying security headers only to certain routes while leaving others unprotected, creating a security gap that attackers can target.

Hapi-Specific Detection

Detecting clickjacking vulnerabilities in Hapi applications requires examining both the framework's configuration and the runtime behavior of your routes. The first step is to verify that security headers are properly configured across all routes.

Using middleBrick's API scanning capabilities provides comprehensive detection of clickjacking vulnerabilities. When you scan your Hapi application with middleBrick, it automatically tests for missing X-Frame-Options headers and inadequate CSP frame-ancestors directives. The scanner evaluates whether your endpoints can be embedded in iframes from external domains, which is the core clickjacking vulnerability.

npm install -g middlebrick
middlebrick scan https://yourapp.com

middleBrick's LLM security scanning also detects clickjacking-related issues in AI-powered Hapi endpoints, where prompt injection attacks might be combined with UI manipulation techniques.

For manual detection in Hapi, examine your server configuration and route handlers. Check if you're using the hapi-helmet plugin or similar security middleware. Without it, you need to manually verify security headers:

server.ext('onPreResponse', (request, h) => {
  const response = request.response;
  if (response.isBoom) {
    return h.continue;
  }
  
  if (!response.headers['x-frame-options']) {
    console.warn('Missing X-Frame-Options header on route:', request.path);
  }
  
  return h.continue;
});

Another detection method involves testing your application's response to iframe embedding attempts. You can use browser developer tools to inspect whether your sensitive routes can be loaded within iframes from different origins. Pay special attention to routes that perform state-changing operations or access sensitive data.

Plugin-based detection is also crucial in Hapi. Review all plugins in your application to ensure none are inadvertently removing security headers. This is particularly important when using plugins that modify responses or handle static assets.

Hapi-Specific Remediation

Remediating clickjacking vulnerabilities in Hapi applications involves implementing consistent security headers and leveraging Hapi's plugin architecture for comprehensive protection. The most effective approach uses the hapi-helmet plugin, which provides standardized security header management.

const Hapi = require('@hapi/hapi');
const helmet = require('hapi-helmet');

const init = async () => {
  const server = Hapi.server({
    port: 3000,
    host: 'localhost'
  });

  await server.register({
    plugin: helmet,
    options: {
      contentSecurityPolicy: {
        directives: {
          defaultSrc: ["'self'"],
          frameAncestors: ["'none'"], // Prevents clickjacking
          styleSrc: ["'self'", 'https://fonts.googleapis.com'],
          fontSrc: ["'self'", 'https://fonts.gstatic.com']
        }
      },
      xframe: 'deny' // X-Frame-Options header
    }
  });

  server.route({
    method: 'GET',
    path: '/admin',
    handler: (request, h) => {
      return h.view('admin');
    }
  });

  await server.start();
  console.log('Server running on %s', server.info.uri);
};

init();

For applications that need more granular control, implement a custom response extension to add security headers:

server.ext('onPreResponse', (request, h) => {
  const response = request.response;
  
  if (response.isBoom || response.statusCode !== 200) {
    return h.continue;
  }

  // Add security headers to all HTML responses
  if (response.source && response.source.template) {
    response.headers['x-frame-options'] = 'DENY';
    response.headers['content-security-policy'] = "frame-ancestors 'none'";
  }

  return h.continue;
});

When dealing with Hapi's plugin ecosystem, ensure security headers are applied at the server level before any other plugins that might modify responses. The order of plugin registration matters significantly for security header effectiveness.

For routes that legitimately need to be embedded (rare), use the CSP frame-ancestors directive to restrict embedding to specific trusted origins:

server.ext('onPreResponse', (request, h) => {
  const response = request.response;
  
  if (request.path === '/embeddable-widget') {
    response.headers['content-security-policy'] = "frame-ancestors 'self' https://trusted.com";
  } else {
    response.headers['x-frame-options'] = 'DENY';
    response.headers['content-security-policy'] = "frame-ancestors 'none'";
  }
  
  return h.continue;
});

Another Hapi-specific consideration is handling WebSocket connections and SSE (Server-Sent Events), which can also be vulnerable to clickjacking-like attacks. Ensure these connections are properly authenticated and consider implementing origin checking for WebSocket upgrades.

For comprehensive protection, combine security headers with frame-busting JavaScript as a defense-in-depth measure:

server.ext('onPreResponse', (request, h) => {
  const response = request.response;
  
  if (response.source && response.source.template) {
    const originalContext = response.context || {};
    response.context = {
      ...originalContext,
      frameBust: "if (top !== self) top.location = self.location;"
    };
  }
  
  return h.continue;
});

Frequently Asked Questions

Can clickjacking affect authenticated Hapi API endpoints?
Yes, clickjacking can affect authenticated endpoints if the user's session cookies are sent automatically with requests. Even with authentication, if a malicious site embeds your Hapi application in an iframe and tricks the user into clicking, the browser will include the user's session cookies, potentially allowing the attacker to perform actions on behalf of the authenticated user. This is why security headers like X-Frame-Options and CSP frame-ancestors are essential regardless of authentication status.
How does middleBrick detect clickjacking vulnerabilities in Hapi applications?
middleBrick detects clickjacking vulnerabilities by scanning your Hapi application's endpoints and testing for the presence of security headers like X-Frame-Options and Content-Security-Policy frame-ancestors directives. The scanner attempts to embed your endpoints in iframes from different origins to verify whether clickjacking is possible. It also analyzes your OpenAPI/Swagger specifications to identify endpoints that might be vulnerable based on their functionality, then validates these findings against the actual runtime behavior of your application.