Dangling Dns in Express with Api Keys
Dangling Dns in Express with Api Keys — how this specific combination creates or exposes the vulnerability
A dangling DNS record occurs when a hostname (e.g., dev-api.example.com) still points to an IP address, but the target service or application has been decommissioned or reconfigured. In Express applications that rely on API keys for outbound service authentication, this combination can expose internal or third‑party endpoints and credentials. If your Express code resolves a hostname at startup or runtime and uses a static API key for that endpoint, and the DNS record points to an environment you no longer control, an attacker who can influence DNS (e.g., via a compromised registrar or a vulnerable internal resolver) may redirect the hostname to a server they control.
Consider an Express service that calls an external vendor’s API using an API key stored in environment variables and a hostname configured via environment or config. If the vendor decommissions an old endpoint and the DNS record is not cleaned up promptly, the hostname might resolve to an attacker’s server. Because the API key is often static and embedded in the application logic or environment, the attacker can capture it by running a listener on the dangling host. This can lead to API key theft, unauthorized access to downstream services, and lateral movement within your infrastructure. The risk is especially acute when the Express app uses the same API key for multiple downstream calls or when logging and error handling inadvertently expose the key in responses or logs.
An attacker does not need to exploit the Express app itself; they exploit the DNS misconfiguration. Once the hostname resolves to the attacker’s infrastructure, any request from the Express app sends the API key to the attacker. This scenario is common when migrating services, during testing, or when third‑party domains are not properly retired. middleBrick’s unauthenticated scan detects such dangling DNS by resolving hostnames used in outbound configurations and comparing them against observed endpoints; combined with API key exposure checks, it can surface misconfigured or stale references before they are weaponized.
In practice, you should audit DNS records for hostnames referenced by your Express app and verify that they point only to active, trusted endpoints. Ensure API keys are scoped with minimal permissions and rotated regularly. If an API key is exposed due to a dangling DNS resolution, treat it as compromised and rotate it immediately. middleBrick’s LLM/AI Security checks do not apply here, but its inventory and external endpoint validation help identify inconsistencies between declared and resolved endpoints, supporting a more robust API security posture aligned with OWASP API Top 10 and related compliance frameworks.
Api Keys-Specific Remediation in Express — concrete code fixes
To mitigate risks related to API keys and dangling DNS in Express, adopt least‑privilege keys, avoid hardcoding secrets, and validate outbound endpoints. Below are concrete, working examples that demonstrate secure handling of API keys in Express applications.
First, store API keys in environment variables and load them securely. Do not commit keys to source control. Use a .env file during development and rely on your platform’s secret manager in production.
// server.js
require('dotenv').config();
const express = require('express');
const axios = require('axios');
const app = express();
const PORT = process.env.PORT || 3000;
// Read API key from environment
const API_KEY = process.env.VENDOR_API_KEY;
if (!API_KEY) {
console.error('VENDOR_API_KEY is not defined in environment.');
process.exit(1);
}
app.get('/proxy', async (req, res) => {
try {
const response = await axios.get('https://${process.env.VENDOR_HOST}/data', {
headers: { Authorization: `Bearer ${API_KEY}` }
});
res.json(response.data);
} catch (err) {
console.error('Outbound request failed:', err.message);
res.status(502).json({ error: 'upstream_error' });
}
});
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
Second, validate the resolved host before making requests. You can perform a DNS lookup at startup to ensure the hostname resolves to an expected IP range or passes a health check. This reduces the chance of inadvertently sending keys to a dangling host.
// dns-validate.js
const dns = require('dns').promises;
const https = require('https');
async function validateHost(hostname, expectedFingerprint) {
let resolved;
try {
resolved = await dns.resolve(hostname, 'A');
} catch (err) {
throw new Error(`DNS resolution failed for ${hostname}: ${err.message}`);
}
if (!resolved || resolved.length === 0) {
throw new Error(`No IPs resolved for ${hostname}`);
}
// Optional: perform a lightweight HTTPS request and validate certificate fingerprint
return new Promise((resolve, reject) => {
const req = https.get(`https://${hostname}/health`, (res) => {
const cert = res.connection.getPeerCertificate();
// Simplified: in production, compute and compare fingerprint
if (expectedFingerprint && cert.fingerprint !== expectedFingerprint) {
return reject(new Error('Certificate fingerprint mismatch'));
}
resolve({ ips: resolved, cert: cert.fingerprint });
});
req.on('error, reject');
req.setTimeout(5000, () => req.destroy());
});
}
// Usage at startup
(async () => {
try {
const info = await validateHost(process.env.VENDOR_HOST, process.env.VENDOR_CERT_FINGERPRINT);
console.log('Host validated:', info);
} catch (err) {
console.error('Startup validation failed:', err.message);
process.exit(1);
}
})();
Third, rotate keys regularly and scope them to specific routes or methods. If your vendor supports it, use per-request tokens or temporary credentials instead of long-lived API keys. Combine this with runtime environment validation to ensure the host your app connects to matches the intended target, reducing exposure from dangling DNS.
Finally, integrate middleBrick’s CLI into your workflow to scan from terminal with middlebrick scan <url> and surface DNS and API key exposure findings. For CI/CD, add API security checks to your pipeline with the GitHub Action to fail builds if risk scores drop below your threshold, and use the MCP Server to scan APIs directly from your AI coding assistant during development.