HIGH dangling dnskoajavascript

Dangling Dns in Koa (Javascript)

Dangling DNS in Koa with JavaScript — how this specific combination creates or exposes the vulnerability

Dangling DNS occurs when a subdomain points to a service that no longer exists (e.g., a deleted cloud resource, expired SaaS tenant, or decommissioned third-party integration), but the DNS record remains active. In a Koa.js application, this vulnerability is exposed when the app makes outbound HTTP requests to external domains based on user-controlled input without proper validation. For example, if a Koa route uses ctx.request.query.url to fetch data from an external API and passes it directly to fetch or axios, an attacker can manipulate the parameter to target a dangling subdomain they control or that points to a vulnerable internal service.

Consider a Koa endpoint designed to preview URLs: it accepts a url query parameter, fetches the content, and returns metadata. If the application does not validate that the hostname is in an allowed list, an attacker could supply a URL like http://dangling-service.example.com/internal-admin. If dangling-service.example.com once pointed to a now-deleted AWS Elastic Load Balancer but the DNS record still exists, an attacker could re-register the domain (if expired) or exploit misconfigured cloud resources to host malicious content. The Koa app, unaware, would make the request and potentially expose internal networks via SSRF or leak sensitive data.

This risk is amplified in Koa because of its minimalist, middleware-driven design. Developers often implement custom fetch logic without centralized validation, relying on ad-hoc checks. Unlike frameworks with built-in URL validation (e.g., Express with helmet or specialized middleware), Koa requires explicit effort to sanitize outbound requests. The combination of Koa’s flexibility and missing outbound request controls makes dangling DNS exploitation a realistic path to SSRF, cloud metadata access, or internal service enumeration when paired with user-influenced outbound traffic.

JavaScript-Specific Remediation in Koa — concrete code fixes

To mitigate dangling DNS risks in Koa, implement strict outbound request validation using an allowlist of permitted hostnames. This must be done at the middleware level before any outbound HTTP request is made. Below is a syntactically correct Koa middleware that validates the hostname of a user-provided URL against a predefined list of allowed domains.

const Koa = require('koa');
const Router = require('koa-router');

const app = new Koa();
const router = new Router();

// Define allowed outbound destinations
const ALLOWED_HOSTS = new Set([
  'api.example.com',
  'data.trustedpartner.org',
  'graphs.metrics.net'
]);

// Middleware to validate outbound URL hostname
function validateOutboundURL() {
  return async (ctx, next) => {
    const { url } = ctx.query;
    if (!url) {
      ctx.status = 400;
      ctx.body = { error: 'Missing url parameter' };
      return;
    }

    let parsed;
    try {
      parsed = new URL(url);
    } catch (err) {
      ctx.status = 400;
      ctx.body = { error: 'Invalid URL format' };
      return;
    }

    const hostname = parsed.hostname.toLowerCase();

    // Optional: block IP addresses to prevent DNS bypass
    if (/^\d+\.\d+\.\d+\.\d+$/.test(hostname) ||
        /^\[[0-9a-f:]+\]$/.test(hostname)) {
      ctx.status = 400;
      ctx.body = { error: 'IP addresses are not allowed' };
      return;
    }

    if (!ALLOWED_HOSTS.has(hostname)) {
      ctx.status = 403;
      ctx.body = { error: 'Hostname not allowed' };
      return;
    }

    // Attach parsed URL to state for use in route handler
    ctx.state.parsedURL = parsed;
    await next();
  };
}

// Route that uses validated URL
router.get('/fetch-metadata', validateOutboundURL(), async (ctx) => {
  const { parsedURL } = ctx.state;
  try {
    const response = await fetch(parsedURL.toString(), {
      timeout: 5000,
      redirect: 'manual' // Prevent automatic redirect attacks
    });
    if (!response.ok) {
      ctx.status = 502;
      ctx.body = { error: 'Upstream request failed' };
      return;
    }
    const data = await response.text();
    ctx.body = { metadata: { length: data.length, contentType: response.headers.get('content-type') } };
  } catch (err) {
    ctx.status = 500;
    ctx.body = { error: 'Request failed', details: err.message };
  }
});

app.use(router.routes());
app.listen(3000);

This approach ensures that even if a dangling DNS record points to an attacker-controlled domain, the request is blocked unless the hostname is explicitly allowed. Combine this with network-level controls (egress filtering) and regular DNS inventory audits to reduce exposure. middleBrick can help detect such misconfigurations by scanning for SSRF vectors and identifying outbound requests to unauthorized domains during its black-box testing of the unauthenticated attack surface.

Frequently Asked Questions

How does dangling DNS differ from regular SSRF in a Koa application?
Regular SSRF involves tricking a server into making requests to unintended internal or external destinations, often via IP addresses or known internal hostnames. Dangling DNS is a specific subset where the vulnerability relies on a DNS record that still resolves but points to a deprovisioned or expired resource—making it harder to detect via static allowlists since the domain may appear legitimate. In Koa, both are mitigated by validating the hostname of outbound requests against a strict allowlist, but dangling DNS requires additional vigilance because the domain itself may not be malicious—it’s the dangling state that enables exploitation when combined with cloud misconfigurations or subdomain takeover risks.
Can I use a package like 'is-valid-hostname' to validate outbound URLs in Koa instead of writing my own logic?
While packages like 'is-valid-hostname' can check syntactic validity, they do not enforce business-logic allowlists. For security, you must combine syntax validation with an explicit list of permitted hostnames. Relying solely on general validation libraries leaves you vulnerable to dangling DNS or SSRF if an attacker uses a syntactically valid but unauthorized hostname. In Koa, implement a two-step check: first validate URL syntax (using the built-in URL constructor or a trusted library), then verify the hostname is in your approved set. This ensures both correctness and security.