HIGH dns cache poisoningfeathersjsjwt tokens

Dns Cache Poisoning in Feathersjs with Jwt Tokens

Dns Cache Poisoning in Feathersjs with Jwt Tokens — how this specific combination creates or exposes the vulnerability

DNS cache poisoning (also referred to as DNS spoofing) manipulates DNS responses to redirect a client or server to a malicious IP. In FeathersJS applications that rely on JWT tokens for authentication and authorization, this attack can undermine the trust boundary that JWTs are meant to provide.

FeathersJS typically uses HTTP transports (REST or Socket.io). If a FeathersJS service resolves a hostname—such as a database, internal microservice, or authorization endpoint—using a client-side DNS lookup that is cacheable and poisoned, the application may be directed to an attacker-controlled host. Even when JWT tokens are used to sign and validate requests, the token’s integrity and the channel’s confidentiality can be bypassed if the transport itself is redirected.

Consider a FeathersJS service that calls an internal user-management API validated by JWT access tokens. If an attacker poisons the DNS record for the internal service hostname, the FeathersJS client may unknowingly send JWTs over a malicious endpoint. Because JWTs are often passed in the Authorization header, intercepted tokens can be reused, and the attacker may learn patterns (e.g., token lifetimes, structure) that facilitate further compromise. In setups where FeathersJS also uses server-side service discovery or dynamic endpoint resolution, poisoned DNS can cause the server to route requests to a rogue service that mimics the legitimate API.

JWTs do not prevent DNS poisoning; they only protect token integrity and claims. If the channel is redirected, the attacker may perform token replay or inject malicious tokens if other defenses (such as strict host validation and transport-layer encryption) are absent. In microservice architectures common in FeathersJS deployments, poisoned DNS can lead to privilege escalation when tokens intended for a secure internal endpoint are sent to an attacker, or when the poisoned resolution affects service-to-service calls that rely on JWT-based mTLS alternatives or metadata propagation.

Real-world attack patterns that align with this risk include OWASP API Top 10 A05:2023 Security Misconfiguration and A07:2023 Identification and Authentication Failures. A relevant example is CVE-2020-8204, where misconfigured trust in certain client-side resolutions allowed redirection to malicious endpoints, emphasizing the need to validate resolved endpoints and enforce secure channels even when JWTs are present.

Jwt Tokens-Specific Remediation in Feathersjs — concrete code fixes

Remediation centers on ensuring that JWT usage does not rely on potentially compromised network resolution and that transport integrity is enforced. Below are concrete steps and code examples for FeathersJS applications.

  • Pin hostnames to IPs via application-level configuration and avoid runtime DNS lookups for sensitive endpoints. Instead of relying on DNS for service discovery, use static IPs or a hardened service registry with validated entries.
  • Enforce strict transport security by requiring HTTPS for all API communication, including service-to-service calls. Validate server certificates and avoid disabling TLS verification.
  • Bind JWT validation to the authenticated session and ensure tokens are not accepted from untrusted or unexpected origins. Use origin checks and referrer policies on HTTP endpoints.

Example: A FeathersJS service that uses JWT authentication with a static, trusted API endpoint and HTTPS enforcement.

// src/app.js
const feathers = require('@feathersjs/feathers');
const express = require('@feathersjs/express');
const jwt = require('@feathersjs/authentication-jwt');
const configuration = require('./configuration');

const app = express(feathers());

// Enforce HTTPS in production by rejecting non-secure origins
app.set('trust proxy', 1);
app.use((req, res, next) => {
  if (process.env.NODE_ENV === 'production' && !req.secure) {
    return res.status(400).send('HTTPS required');
  }
  next();
});

// Static, validated service endpoint to avoid DNS dependency
const INTERNAL_API_HOST = process.env.INTERNAL_API_HOST || '10.0.3.10';
const INTERNAL_API_PORT = process.env.INTERNAL_API_PORT || 3031;

app.configure(jwt({
  secret: configuration.get('auth:jwtSecret'),
  algorithms: ['RS256'],
  // Validate issuer and audience strictly
  issuer: 'https://auth.yourcompany.com',
  audience: 'https://api.yourcompany.com'
}));

// Example service that calls an internal API with a pinned host
const { create: createTokenService } = require('feathers-http');
app.use('/introspect', createTokenService({
  name: 'introspect',
  host: INTERNAL_API_HOST,
  port: INTERNAL_API_PORT,
  https: true,
  // Pin certificate fingerprint to further mitigate poisoning
  caFingerprint: 'aa:bb:cc:dd:ee:ff:00:11:22:33:44:55:66:77:88:99:00:aabb:ccdd'
})));

// Validate JWT origin on each request
app.hooks({
  before: {
    all: [context => {
      const allowedOrigins = ['https://yourcompany.com', 'https://app.yourcompany.com'];
      const origin = context.params.headers.origin;
      if (origin && !allowedOrigins.includes(origin)) {
        throw new Error('Invalid origin');
      }
      return context;
    }]
  }
});

module.exports = app;

Example: A client-side hook that verifies token binding to the expected endpoint hostname, preventing acceptance of tokens intended for a different resolved host.

// src/hooks/token-boundary.js
module.exports = function tokenBoundaryHook(options) {
  return async context => {
    const { token } = context.params.headers || {};
    if (token) {
      // Ensure the request target matches the expected service host
      const expectedHost = process.env.FEATHERS_API_HOST || 'api.yourcompany.com';
      const targetHost = new URL(context.path.startsWith('http') ? context.path : `https://${expectedHost}`).hostname;
      // Optionally validate token 'host' claim if present
      // Implement additional checks as needed
      context.params.headers['x-target-host'] = targetHost;
    }
    return context;
  };
};

// Usage in service configuration
const app = require('feathers')();
app.configure({
  path: '/messages',
  host: process.env.FEATHERS_API_HOST
}).hooks({
  before: {
    all: [require('./hooks/token-boundary')]
  }
});

By combining static endpoint definitions, strict transport security, and origin validation, the risk of DNS cache poisoning impacting JWT-protected FeathersJS services is significantly reduced.

Frequently Asked Questions

Can DNS cache poisoning lead to JWT token theft even if HTTPS is used?
Yes, if an attacker successfully redirects DNS resolution to a malicious server that presents a valid TLS certificate (e.g., via compromised CAs or certificate transparency weaknesses), HTTPS alone does not prevent token theft. Mitigate by pinning certificates and validating endpoints.
Does middleBrick scan for DNS misconfigurations that could affect JWT-protected APIs?
middleBrick scans the unauthenticated attack surface for issues such as Security Misconfiguration and Data Exposure. Use the CLI (middlebrick scan ) or Web Dashboard to review findings and apply remediation guidance.