Dns Rebinding in Express (Javascript)
Dns Rebinding in Express with Javascript — how this specific combination creates or exposes the vulnerability
DNS rebinding is a client-side attack that manipulates DNS responses to make a victim’s browser believe a remote host is reachable at an IP address that is not publicly routable (for example, 127.0.0.1 or a local network address). When Express is used to serve an application or API without protections that account for the browser’s same-origin policy, a page served from one origin can make requests to an internal endpoint on behalf of the user, exposing internal services through the victim’s network path.
In this scenario, the attacker registers a domain (example.bad) and configures authoritative DNS to return a public IP initially (e.g., a CDN IP). After the victim loads the attacker’s page, JavaScript in the page periodically resolves the same domain to a private IP such as 127.0.0.1. Because the victim’s browser enforces same-origin policy based on the resolved IP’s perceived network location, the attacker’s JavaScript can make privileged requests to internal APIs that Express hosts locally or on the internal network. These requests may bypass expected network boundaries and access endpoints that were intended only for local consumption (for example, a status or admin interface on localhost).
Express itself does not perform network boundary checks; it serves HTTP responses according to the routes and middleware you define. If your Express routes do not validate the origin or enforce network-level restrictions, JavaScript running in the browser can abuse this behavior. For example, an Express endpoint that returns sensitive internal data (e.g., /api/internal/status) and relies only on IP-based trust can be called from malicious JavaScript, leading to data exposure or unauthorized actions performed on behalf of the authenticated user.
Because middleBrick tests unauthenticated attack surfaces and runs checks in parallel for input validation and other client-driven concerns, DNS rebinding is surfaced when client-side behaviors enable access to unexpected endpoints. The scanner’s input validation checks can highlight endpoints that accept requests without verifying origin or referer headers, while the broader scan can reveal implicit trust assumptions in your API design. This is why it is important to treat all client-originated requests as potentially untrusted and to apply strict validation and network controls on the server side.
Javascript-Specific Remediation in Express — concrete code fixes
To mitigate DNS rebinding in an Express application, enforce origin and host validation on the server, avoid relying on network topology for security, and design JavaScript clients to assume network-level threats. Below are concrete, idiomatic JavaScript examples for Express that reduce risk.
1. Validate Origin and Host headers
Explicitly check the Origin or Host header and reject requests that do not match an allowlist. This reduces the window for browser-based requests to be accepted from unexpected origins.
const allowedOrigins = ['https://your-app.com', 'https://admin.your-company.com'];
app.use((req, res, next) => {
const origin = req.headers.origin;
const host = req.headers.host;
if (!origin || !allowedOrigins.includes(origin)) {
return res.status(403).json({ error: 'Forbidden origin' });
}
// Optionally also validate host if you rely on it
if (!host || !host.startsWith('api.your-domain.com')) {
return res.status(403).json({ error: 'Forbidden host' });
}
next();
});
2. Restrict network interfaces and bind explicitly
Configure Express to listen only on specific interfaces and avoid binding to all interfaces when internal services should not be exposed. This does not replace origin validation but reduces the attack surface reachable from the browser.
const http = require('http');
const app = require('./app'); // your Express app
const server = http.createServer(app);
const PORT = process.env.PORT || 3000;
const HOST = '127.0.0.1'; // bind to localhost only for local/admin endpoints
server.listen(PORT, HOST, () => {
console.log(`API listening on http://${HOST}:${PORT}`);
});
3. Use CORS middleware with strict configuration
Use a well-maintained CORS package to control which origins can access your endpoints. Avoid wildcard origins for sensitive routes.
const cors = require('cors');
const corsOptions = {
origin: ['https://your-app.com', 'https://trusted-partner.com'],
methods: ['GET', 'POST'],
allowedHeaders: ['Content-Type', 'Authorization'],
credentials: true
};
app.use(cors(corsOptions));
4. Implement per-request checks for sensitive endpoints
For endpoints that expose internal state or admin functions, combine header checks with CSRF tokens or other anti-CSRF protections to ensure requests originate from your own frontend and not from arbitrary HTML pages.
app.get('/api/internal/status', (req, res) => {
const origin = req.headers.origin;
if (origin !== 'https://your-app.com') {
return res.status(403).json({ error: 'Invalid origin' });
}
// Proceed with internal status logic
res.json({ status: 'ok', uptime: process.uptime() });
});
5. Avoid exposing internal endpoints to the public network
Design your Express routes so that administrative or diagnostic endpoints are not bound to public interfaces. If you must expose them, require additional authentication or network-level access controls beyond browser-origin checks.
These JavaScript-centric mitigations focus on server-side validation and network binding, which complement client-side awareness. Note that middleBrick scans detect input validation and CORS misconfigurations; combining the scanner’s findings with these code-level practices reduces the likelihood that a browser-based attacker can leverage DNS rebinding against your Express services.