Clickjacking in Express
How Clickjacking Manifests in Express
Clickjacking in Express applications typically occurs when attackers embed your API's web interface or dashboard inside an invisible iframe, tricking users into performing unintended actions. In Express, this vulnerability often emerges in routes that serve HTML pages with sensitive operations—like admin panels, payment processing, or account management interfaces.
A common Express-specific scenario involves routes that render EJS, Pug, or Handlebars templates without proper frame-busting headers. For example, an admin dashboard route might look like this:
app.get('/admin/dashboard', (req, res) => {
res.render('admin-dashboard', { user: req.user });
});Without protection, an attacker can create a malicious page that loads this dashboard in a hidden iframe and uses CSS positioning to overlay deceptive buttons on top of legitimate UI elements. The user believes they're clicking a "Download Report" button, but they're actually triggering an admin action like "Delete All Users."
Express applications are particularly vulnerable when they serve single-page applications (SPAs) or admin interfaces that rely on client-side JavaScript for critical operations. If these pages don't implement proper X-Frame-Options headers, attackers can create convincing phishing interfaces that harvest credentials or execute unauthorized actions.
Another Express-specific manifestation involves API endpoints that serve HTML forms for state-changing operations. Consider a route that processes payments:
app.post('/api/payments/process', (req, res) => {
const { amount, recipient } = req.body;
// Process payment logic
});If the corresponding GET route that serves the payment form lacks frame protection, an attacker can frame it and trick users into submitting payments to attacker-controlled accounts.
Express-Specific Detection
Detecting clickjacking in Express applications requires examining both the server configuration and the rendered HTML responses. Using middleBrick's API security scanner, you can identify this vulnerability by scanning your Express endpoints. The scanner specifically tests for missing X-Frame-Options headers and Content-Security-Policy directives that prevent framing.
To manually detect clickjacking in your Express app, examine your route handlers that serve HTML content. Look for patterns where you're using res.render(), res.sendFile(), or res.send() to deliver HTML pages without security headers. A vulnerable route might look like:
app.get('/sensitive-operation', (req, res) => {
res.render('sensitive-form');
});middleBrick's scanner will flag this because it can successfully load the page inside an iframe during testing. The scanner also examines your Express middleware stack to identify missing security configurations.
For comprehensive detection, you should scan all routes that serve HTML content, especially those in /admin, /api, and /dashboard paths. middleBrick's continuous monitoring (available in Pro plans) can automatically detect when new routes are added that might be vulnerable to clickjacking.
Another detection method involves testing your Express application with browser developer tools. Right-click on sensitive pages and inspect the response headers. If you don't see X-Frame-Options: DENY or X-Frame-Options: SAMEORIGIN, or a proper CSP frame-ancestors directive, your Express app is vulnerable.
Express-Specific Remediation
Remediating clickjacking in Express applications involves adding proper security headers at the middleware level. The most straightforward approach uses the helmet middleware, which is specifically designed for Express security:
const helmet = require('helmet');
app.use(helmet({
frameguard: {
action: 'deny' // or 'sameorigin' for same-domain framing
}
}));This automatically adds the X-Frame-Options header to all responses. For more granular control, you can configure it per-route:
app.get('/admin/dashboard', (req, res) => {
res.setHeader('X-Frame-Options', 'DENY');
res.render('admin-dashboard');
});Alternatively, use Content-Security-Policy for modern browsers:
app.use(helmet({
contentSecurityPolicy: {
directives: {
frameAncestors: ["'none'"]
}
}
}));For Express applications serving SPAs, you might want different policies for different routes. Use route-specific middleware:
const noClickjacking = (req, res, next) => {
res.setHeader('X-Frame-Options', 'DENY');
res.setHeader('Content-Security-Policy', "frame-ancestors 'none'");
next();
};
app.use('/admin', noClickjacking, adminRouter);
app.use('/api', noClickjacking, apiRouter);middleBrick's scanner can verify these fixes by attempting to frame your protected endpoints. After implementing these headers, your Express app should receive an improved security score, as middleBrick tests the actual HTTP headers returned by your server.
For legacy browser support, combine both X-Frame-Options and CSP headers, as some older browsers only respect the former. middleBrick's comprehensive scanning checks both mechanisms to ensure complete protection.