Clickjacking in Feathersjs (Javascript)
Clickjacking in Feathersjs with Javascript — how this specific combination creates or exposes the vulnerability
Clickjacking is a client-side injection vulnerability where an attacker tricks a user into clicking on a transparent or disguised UI element inside an invisible frame. In a FeathersJS application built with Javascript, this typically occurs when HTTP response headers do not enforce frame-embedding restrictions. FeathersJS itself does not set these headers by default, so if your app is served without X-Frame-Options or Content-Security-Policy headers, an attacker can embed your authenticated pages inside an <iframe> and overlay interactive controls to hijack actions such as account updates or API calls.
Because FeathersJS often serves JSON APIs and can also render server-side views (e.g., with @feathersjs/views), the framework can expose endpoints that return HTML pages. If these pages are rendered without anti-framing protections, a malicious site can load them in an invisible frame and use CSS and JavaScript to position buttons or links under the user’s cursor. When the user is authenticated (e.g., with session cookies), any unintended action triggered in the hidden frame may execute with the victim’s privileges. This is especially risky for state-changing endpoints like POST, PUT, or DELETE routes defined via FeathersJS services.
Middleware configuration in FeathersJS plays a key role. If you use custom hooks or static assets middleware without explicitly setting security headers, the responses may be framed unintentionally. For example, serving an admin UI via FeathersJS static assets without Content-Security-Policy: frame-ancestors 'none' allows any site to embed the page. Additionally, if the app supports CORS but does not restrict origins strictly, it may further facilitate clickjacking scenarios by allowing unintended domains to interact with authenticated sessions.
Real-world attack patterns mirror classic OWASP Top 10 A05:2021 — Security Misconfiguration, where missing security headers enable clickjacking. Unlike black-box scanning tools that detect missing headers, a targeted exploit can combine CSS z-index manipulation, pointer-events, and JavaScript event listeners to create invisible overlays. This is why scanning your FeathersJS endpoints with a tool that checks for these missing controls (such as verifying the presence of X-Frame-Options and CSP frame-ancestors) is important to identify the attack surface before adversaries do.
Javascript-Specific Remediation in Feathersjs — concrete code fixes
To remediate clickjacking in a FeathersJS application using Javascript, you must enforce frame-embedding restrictions via HTTP response headers. The most direct approach is to set X-Frame-Options to DENY or SAMEORIGIN. For modern browsers, the Content-Security-Policy header with frame-ancestors provides finer control. These headers should be applied globally in your FeathersJS configuration or within a dedicated middleware hook.
Below is a complete example of a FeathersJS hook that sets both headers on every response. This hook can be added to your src/hooks/index.js and registered before your service routes to ensure protection across all endpoints that use the hook pipeline.
// src/hooks/security-headers.js
module.exports = function () {
return async context => {
const { headers } = context.result || context.app ? context.app.get('headers') || {} : {};
// Set X-Frame-Options to prevent framing entirely
context.app.set('X-Frame-Options', 'DENY');
// Set Content-Security-Policy frame-ancestors to disallow embedding
context.app.set('Content-Security-Policy', "default-src 'self'; frame-ancestors 'none'");
return context;
};
};
Register the hook in your FeathersJS entry point (e.g., src/index.js) so it runs for every request:
const feathers = require('@feathersjs/feathers');
const express = require('@feathersjs/express');
const securityHeaders = require('./hooks/security-headers');
const app = express(feathers());
// Apply security headers hook globally
app.configure(securityHeaders());
// Your services and other configuration
app.use('/messages', require('./services/messages'));
module.exports = app;
If you are using server-side views (e.g., EJS or Pug via @feathersjs/views), ensure the headers are set before rendering. You can also apply the headers conditionally for specific routes or disable them for trusted admin origins by checking request host or using an environment variable.
For SPAs or API-only setups, ensure your static assets middleware does not inadvertently allow framing. If you use the @feathersjs/express static helper, combine it with the same security headers hook to guarantee that all responses include Content-Security-Policy and X-Frame-Options.
Note that middleBrick’s scans can verify whether these headers are present and flag missing protections. The CLI (middlebrick scan <url>) and Web Dashboard can surface clickjacking-related findings, and the Pro plan’s continuous monitoring can alert you if a future deployment removes these headers.