HIGH clickjackingsailsjavascript

Clickjacking in Sails (Javascript)

Clickjacking in Sails with Javascript — how this specific combination creates or exposes the vulnerability

Clickjacking is a client-side attack where an attacker tricks a user into interacting with invisible or disguised UI elements. In a Sails application that serves HTML views and uses JavaScript heavily on the client, misconfigured HTTP headers and insecure view templates can enable clickjacking. Sails does not set frame-denying headers by default, so if a page is rendered without an explicit X-Frame-Options or Content-Security-Policy (frame-ancestors), an attacker can embed the app in an <iframe> and overlay interactive elements to hijack clicks.

When Sails serves pages that include inline JavaScript or dynamically rendered partials, the risk increases if those scripts manipulate DOM elements that could be overlaid. For example, a vulnerable Sails view might render a form with an unprotected <button> or link, while an attacker’s page uses CSS and JavaScript to position an invisible iframe and map click coordinates to sensitive actions (such as approving a transaction or changing an email). Because Sails often uses JavaScript on the frontend to bind events or make AJAX requests, an attacker can synchronize overlays with user gestures, making the interaction seamless.

Additionally, if Sails APIs or controllers expose endpoints that perform state-changing operations without verifying the request origin (e.g., missing CSRF tokens for unsafe methods), clickjacking becomes more impactful. Even when using JavaScript frameworks client-side, server-side decisions must not rely solely on the assumption that requests originate from the intended UI. Without proper anti-clickjacking headers and secure-by-default view configurations, Sails applications remain exposed, particularly when JavaScript manipulates the DOM in ways that can be obscured by overlays.

Javascript-Specific Remediation in Sails — concrete code fixes

Remediation focuses on HTTP headers, CSP, and safe JavaScript practices. Headers should be set globally in Sails to prevent framing, and CSP should restrict frame ancestors. For JavaScript, avoid unsafe practices that make UI elements easy to overlay, and ensure event handlers validate context.

1. Set anti-clickjacking headers

Configure Sails to send X-Frame-Options and Content-Security-Policy headers. In a Sails app, this is commonly done in config/http.js.

module.exports.http = {
  middleware: {
    order: ['startRequestTimer', 'cookieParser', 'session', 'mySecurityHeaders', 'bodyParser', 'handleBodyParserError', 'compress', 'methodOverride', 'poweredBy', '$custom', 'www', 'router'],
    mySecurityHeaders: function(req, res, next) {
      res.set('X-Frame-Options', 'DENY');
      res.set(
        'Content-Security-Policy',
        "default-src 'self'; frame-ancestors 'none';"
      );
      return next();
    }
  }
};

2. Secure JavaScript event handling

Ensure that critical UI interactions are not easily overlapped. Use pointer events with hit-testing and avoid placing interactive elements under transparent or absolutely positioned layers. If you must use overlays, validate that they are intentional.

document.addEventListener('click', function(e) {
  // Example: ensure clicks on critical buttons are not intercepted
  const button = e.target.closest('.secure-action');
  if (!button) return;
  // Verify the element is not obscured by checking bounding rect
  const rect = button.getBoundingClientRect();
  if (e.clientX < rect.left || e.clientX > rect.right || e.clientY < rect.top || e.clientY > rect.bottom) {
    console.warn('Click intercepted by overlay');
    return;
  }
  // Proceed with action
  fetch('/api/secure-action', { method: 'POST', credentials: 'include' });
});

3. Avoid unsafe HTML in partials

When rendering dynamic content in Sails views (e.g., EJS), ensure you do not inadvertently expose click targets via unsanitized user input. Use strict escaping and avoid injecting raw HTML that could be manipulated by attackers.

<% if (userProvidedContent) { %>
  <div><%- userProvidedContent %></div> <!-- XSS risk, avoid -->
<% } else { %>
  <div><%= userProvidedContent %></div> <!-- Escaped output -->
<% } %>

4. Protect AJAX endpoints

Ensure that state-changing AJAX requests include CSRF tokens and validate the Origin header. Sails has built‑in CSRF protection for forms; for APIs, enforce origin checks.

module.exports.security = {
  csrf: true,
  csrfCookie: 'csrfToken',
  csrfHeader: 'x-csrf-token'
};

// In a controller
updateEmail: async function(req, res) {
  if (!req.isOriginAllowed('https://trusted.example.com')) {
    return res.unauthorized('Invalid origin');
  }
  // proceed with update
}

Frequently Asked Questions

Does Sails set secure HTTP headers by default to prevent clickjacking?
No. Sails does not set X-Frame-Options or Content-Security-Policy frame-ancestors headers by default. You must configure these headers explicitly in config/http.js to protect against clickjacking.
Can client-side JavaScript in Sails apps be exploited for clickjacking even if server headers are correct?
Yes. If JavaScript places interactive elements under opaque or absolute overlays, or if event handlers do not validate pointer coordinates, attackers can still hijack clicks. Secure JavaScript practices and testing with overlay simulations are necessary alongside proper headers.