HIGH dns rebindingadonisjs

Dns Rebinding in Adonisjs

How Dns Rebinding Manifests in Adonisjs

Dns Rebinding in Adonisjs applications typically exploits the framework's default CORS configuration and HTTP client behavior. When Adonisjs serves APIs with permissive CORS settings, an attacker can register a malicious domain that resolves to their own IP, then rapidly switch DNS records to point to the victim's internal network.

The classic Adonisjs vulnerability pattern involves an API endpoint that accepts URLs as parameters and makes internal HTTP requests. Consider this common pattern in Adonisjs controllers:

class ExternalDataService {
  async fetchData({ request }) {
    const url = request.input('endpoint');
    const response = await axios.get(url); // Vulnerable to DNS rebinding
    return response.data;
  }
}

The issue compounds when combined with Adonisjs's default CORS middleware. Many Adonisjs applications enable:

// config/cors.js
module.exports = {
  origin: true, // Allows any origin
  methods: ['GET', 'POST', 'PUT', 'DELETE'],
  credentials: true
}

This permissive configuration, paired with URL-based request handling, creates an attack vector. An attacker's malicious site can trigger requests that appear to originate from the same origin due to DNS rebinding, bypassing CORS protections.

Adonisjs's HTTP client (axios) doesn't implement DNS pinning by default, making it susceptible to rebinding attacks. When processing a URL parameter, the client resolves the hostname at request time, allowing the DNS switch to redirect traffic to internal IPs like 192.168.1.1 or 10.0.0.1.

Another Adonisjs-specific manifestation occurs with WebSocket connections. Adonisjs's WebSocket server, when configured without origin verification, can be targeted by rebinding attacks that hijack authenticated sessions:

const ws = require('@adonisjs/websocket-server')

const server = ws.Server;
server.listen(3333); // No origin verification by default

The framework's reliance on environment variables for configuration can also introduce rebinding risks if internal services are referenced by hostname rather than IP, allowing DNS manipulation to redirect traffic.

Adonisjs-Specific Detection

Detecting DNS rebinding in Adonisjs requires examining both configuration files and runtime behavior. Start by auditing your config/cors.js file for overly permissive settings:

// Dangerous configuration
module.exports = {
  origin: true, // Any origin allowed
  methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'],
  credentials: true,
  allowedHeaders: ['*']
}

Use middleBrick's API security scanner to identify these vulnerabilities automatically. The scanner tests your Adonisjs endpoints against DNS rebinding scenarios without requiring credentials:

npx middlebrick scan https://your-adonis-app.com/api/data

middleBrick specifically checks for:

  • Permissive CORS configurations that allow DNS rebinding bypasses
  • Endpoints accepting URL parameters that could be exploited
  • Internal network access attempts from external origins
  • WebSocket endpoints without proper origin verification
  • Configuration files exposing internal service references

For code-level detection, implement middleware that validates request origins against a whitelist:

class OriginValidator {
  async handle({ request, response }, next) {
    const allowedOrigins = ['https://yourdomain.com'];
    const origin = request.header('origin');
    
    if (!allowedOrigins.includes(origin)) {
      return response.status(403).send('Forbidden origin');
    }
    
    await next();
  }
}

// Register in start/kernel.js
const globalMiddleware = [
  'App/Middleware/OriginValidator'
]

Monitor your Adonisjs application logs for suspicious patterns: multiple rapid requests to the same hostname that resolve to different IPs, or requests to non-routable IP ranges from external origins.

Adonisjs-Specific Remediation

Remediating DNS rebinding in Adonisjs requires a multi-layered approach. First, secure your CORS configuration by explicitly defining allowed origins:

// config/cors.js
module.exports = {
  origin: ['https://yourdomain.com', 'https://yourapp.com'],
  methods: ['GET', 'POST'],
  credentials: false,
  allowedHeaders: ['Content-Type', 'Authorization']
}

For URL parameter handling, implement strict validation and use IP-based restrictions:

const { validate } = use('Validator');
const { parse } = use('url');

class ExternalDataService {
  async fetchData({ request }) {
    const rules = {
      endpoint: 'required|url',
      allowed_domains: ['yourtrusteddomain.com']
    };
    
    const validation = await validate(request.all(), rules);
    if (validation.fails()) {
      return response.status(400).send('Invalid URL');
    }
    
    const url = request.input('endpoint');
    const parsed = parse(url);
    
    // Block internal network access
    const privateIps = /^(192\.168|10\.|172\.(1[6-9]|2[0-9]|3[0-1]))/;
    if (privateIps.test(parsed.hostname)) {
      return response.status(403).send('Internal network access forbidden');
    }
    
    // Only allow whitelisted domains
    if (!this.isWhitelisted(parsed.hostname)) {
      return response.status(403).send('Domain not allowed');
    }
    
    const response = await axios.get(url, {
      timeout: 5000,
      maxRedirects: 0
    });
    
    return response.data;
  }
  
  isWhitelisted(hostname) {
    const whitelist = ['api.yourtrusteddomain.com', 'yourotherdomain.com'];
    return whitelist.includes(hostname);
  }
}

Implement DNS pinning at the application level to prevent resolution changes during a request:

const dns = require('dns');
const memoizedLookups = new Map();

function dnsLookup(hostname) {
  if (memoizedLookups.has(hostname)) {
    return memoizedLookups.get(hostname);
  }
  
  return new Promise((resolve, reject) => {
    dns.lookup(hostname, (err, address) => {
      if (err) return reject(err);
      memoizedLookups.set(hostname, address);
      resolve(address);
    });
  });
}

// Use in your service
const ip = await dnsLookup(parsed.hostname);
if (this.isPrivateIP(ip)) {
  throw new Error('Private IP blocked');
}

For WebSocket security, implement origin verification middleware:

const ws = require('@adonisjs/websocket-server');

const server = ws.Server;
server.on('connection', (socket) => {
  const origin = socket.request.headers.origin;
  const allowedOrigins = ['https://yourdomain.com'];
  
  if (!allowedOrigins.includes(origin)) {
    socket.terminate();
    return;
  }
});

server.listen(3333);

Finally, integrate middleBrick into your CI/CD pipeline to continuously scan for DNS rebinding vulnerabilities:

# .github/workflows/security.yml
name: Security Scan
on: [push, pull_request]

jobs:
  security:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Run middleBrick Scan
        run: npx middlebrick scan https://staging-yourapp.com
        continue-on-error: true
      - name: Fail on high risk
        if: failure()
        run: exit 1

Frequently Asked Questions

How does DNS rebinding specifically target Adonisjs applications?
Adonisjs applications are vulnerable when they combine permissive CORS configurations with URL parameter handling or WebSocket endpoints. The framework's default settings often allow any origin, and its HTTP client doesn't implement DNS pinning, making it easy for attackers to hijack internal network requests through DNS manipulation.
Can middleBrick detect DNS rebinding vulnerabilities in my Adonisjs API?
Yes, middleBrick specifically tests for DNS rebinding by attempting to access internal network resources through your Adonisjs endpoints. It analyzes your CORS configuration, URL parameter handling, and WebSocket setup to identify vulnerabilities that could be exploited through DNS rebinding attacks.