Dns Rebinding in Express
How Dns Rebinding Manifests in Express
Dns Rebinding in Express applications typically emerges through misconfigured CORS policies and internal service exposure. When Express servers accept requests from any origin without proper validation, they become vulnerable to attackers manipulating DNS records to bypass same-origin protections.
The most common Express-specific scenario involves internal API endpoints that trust the Origin header. Consider an Express server running on localhost:3000 that exposes administrative endpoints:
const express = require('express');
const app = express();
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', req.headers.origin);
res.header('Access-Control-Allow-Credentials', 'true');
next();
app.post('/admin/shutdown', (req, res) => {
if (req.body.password === process.env.ADMIN_PASSWORD) {
process.exit(0);
}
res.status(401).send('Unauthorized');
An attacker registers a domain like evil.com and obtains a TLS certificate. They serve malicious JavaScript that makes requests to their own server, which responds with DNS records pointing to the victim's internal Express server. The victim's browser, having visited evil.com, caches this DNS resolution. When the malicious script subsequently makes requests to evil.com, the browser uses the cached internal IP address, allowing the request to reach the Express server with the Origin header set to evil.com.
Express's flexible middleware system can exacerbate this issue. Custom middleware that trusts client-provided headers or implements IP-based authentication becomes particularly vulnerable. For example:
app.use((req, res, next) => {
const clientIP = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
if (isInternalIP(clientIP)) {
req.internal = true;
}
next();
This middleware trusts the X-Forwarded-For header, which an attacker can manipulate through DNS rebinding to spoof internal IP addresses and gain unauthorized access to internal-only endpoints.
Express-Specific Detection
Detecting DNS rebinding vulnerabilities in Express requires examining both configuration and runtime behavior. Start by analyzing CORS policies and origin validation logic:
const cors = require('cors');
app.use(cors()); // This allows ANY origin by default
// More dangerous patterns
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*'); // Wildcard origin
middleBrick's Express-specific scanning identifies these patterns automatically. The scanner tests unauthenticated endpoints by making requests with manipulated Origin headers and verifying if the server responds with CORS headers that would allow cross-origin exploitation.
Look for these Express-specific indicators during security review:
- CORS middleware without origin validation
- Custom middleware that trusts client IP headers
- Internal API endpoints accessible without authentication
- Administrative endpoints with weak or no authorization
- WebSocket endpoints that accept connections from any origin
middleBrick scans these configurations by attempting to access internal endpoints through simulated DNS rebinding attacks. The scanner maintains a database of common Express internal service ports (3000, 8080, 5000, 8000) and tests whether these can be reached through origin manipulation.
Runtime detection involves monitoring for unusual request patterns. Express applications can implement middleware to detect potential DNS rebinding attempts:
app.use((req, res, next) => {
const isInternal = isPrivateIP(req.ip);
const isExternalOrigin = !isInternal(req.headers.origin);
if (isInternal && isExternalOrigin) {
console.warn('Potential DNS rebinding attempt:', {
ip: req.ip,
origin: req.headers.origin,
url: req.url
});
}
next();
This middleware flags requests where an internal client IP is paired with an external origin header, a classic DNS rebinding signature.
Express-Specific Remediation
Securing Express applications against DNS rebinding requires a defense-in-depth approach. Start with proper CORS configuration:
const cors = require('cors');
// Whitelist specific origins
const allowedOrigins = ['https://yourdomain.com', 'https://yourapp.com'];
app.use(cors({
origin: (origin, callback) => {
if (!origin || allowedOrigins.includes(origin)) {
callback(null, true);
} else {
callback(new Error('Not allowed by CORS'));
}
},
credentials: true
For internal-only endpoints, implement origin validation middleware:
function validateInternalAccess(req, res, next) {
const isInternalRequest = isPrivateIP(req.ip);
const isAllowedOrigin = allowedOrigins.includes(req.headers.origin);
if (isInternalRequest || isAllowedOrigin) {
return next();
}
}Express's built-in trust proxy configuration helps when running behind reverse proxies:
app.set('trust proxy', true); // For production behind proxy
function isPrivateIP(ip) {
const ipNum = ip.split('.').reduce((acc, oct) => acc * 256 + parseInt(oct), 0);
return privateRanges.some(range => ipNum >= range.start && ipNum <= range.end);
For administrative endpoints, implement robust authentication and authorization:
app.post('/admin/shutdown', authenticate, authorizeAdmin, (req, res) => {
// Only accessible after proper auth
middleBrick's continuous monitoring can verify these remediations by periodically scanning your Express APIs and alerting if new DNS rebinding vulnerabilities emerge. The Pro plan's CI/CD integration can automatically fail builds if security scans detect regression in CORS policies or origin validation.