HIGH ssrfadonisjs

Ssrf in Adonisjs

How SSRF Manifests in Adonisjs

Server-Side Request Forgery (SSRF) in Adonisjs applications often occurs through HTTP client usage patterns that accept user-controlled URLs. The framework's HTTP client and request handling create specific attack surfaces that developers must understand.

A common pattern in Adonisjs applications involves accepting URLs from HTTP requests and using them to make outbound requests. For example:

class FileService {
  async downloadFile({ request }) {
    const url = request.input('file_url');
    const response = await axios.get(url); // SSRF vulnerability
    return response.data;
  }
}

This code is vulnerable because an attacker can provide internal network URLs like http://localhost:8080 or http://internal-service:9000, allowing them to probe internal systems through your Adonisjs application.

Adonisjs's dependency injection and service container patterns can inadvertently create SSRF opportunities. Consider this pattern:

class ExternalApiService {
  async callService({ request }) {
    const endpoint = request.input('service_endpoint');
    const config = Config.get('services.external');
    const fullUrl = `${config.base_url}${endpoint}`;
    
    // Vulnerable to SSRF through endpoint parameter
    const response = await Http.get(fullUrl);
    return response.body();
  }
}

Another Adonisjs-specific scenario involves the framework's built-in HTTP client and URL validation. Many developers use validate with url rules without realizing they only check format, not destination:

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

async processUrl({ request }) {
  const rules = {
    target_url: 'required|url'
  };
  
  const validation = await validate(request.all(), rules);
  if (validation.fails()) {
    return {
      success: false,
      message: 'Invalid URL'
    };
  }
  
  // Still vulnerable! Only validates format, not destination
  const response = await Http.get(request.input('target_url'));
  return response.body();
}

Adonisjs applications often integrate with microservices architectures where internal service discovery relies on predictable hostnames. An SSRF vulnerability could allow an attacker to access services like http://redis:6379, http://postgres:5432, or http://vault:8200 through your application.

Adonisjs-Specific Detection

Detecting SSRF vulnerabilities in Adonisjs requires understanding both the framework's patterns and the specific attack surface. middleBrick's black-box scanning approach is particularly effective for Adonisjs applications because it tests the actual runtime behavior without needing source code access.

middleBrick scans Adonisjs applications by submitting test payloads to endpoints that might accept URLs. For SSRF detection, it uses a comprehensive test matrix:

# Using middleBrick CLI to scan an Adonisjs API
middlebrick scan https://api.yourservice.com

# Or integrate into Adonisjs CI/CD
# .github/workflows/security.yml
name: Security Scan
on: [push, pull_request]
jobs:
  ssrf-scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Run middleBrick Scan
        run: |
          npx middlebrick scan https://staging.yourservice.com
        continue-on-error: true
      - name: Fail on high risk
        if: failure()
        run: |
          echo "SSRF vulnerability detected. Review middleBrick report."
          exit 1

middleBrick's SSRF detection for Adonisjs specifically tests for:

  • Localhost and loopback address access (localhost, 127.0.0.1, ::1)
  • Private IP ranges (10.x, 172.16-31.x, 192.168.x)
  • Internal domain resolution (using a custom DNS resolver)
  • Cloud metadata services (http://169.254.169.254 for AWS/Azure)
  • Common service ports (Redis 6379, PostgreSQL 5432, MongoDB 27017)
  • Unix socket access attempts

The scanner analyzes Adonisjs-specific patterns like HTTP client usage in controllers, middleware that processes external URLs, and service classes that make outbound requests. It maps findings to OWASP API Top 10 SSRF category and provides severity scores based on the potential impact.

For development teams, middleBrick's dashboard shows SSRF risk trends across your Adonisjs APIs, helping prioritize remediation efforts. The continuous monitoring feature can alert you when new SSRF vulnerabilities are introduced in your codebase.

Adonisjs-Specific Remediation

Remediating SSRF vulnerabilities in Adonisjs requires a defense-in-depth approach. The framework provides several mechanisms to implement proper controls.

First, implement allowlist-based URL validation using Adonisjs's validation system:

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

async processUrl({ request }) {
  const rules = {
    target_url: 'required|url',
    // Custom validation to check allowed domains
    allowed_domain: 'in:example.com,yourservice.com'
  };
  
  const validation = await validate(request.all(), rules);
  if (validation.fails()) {
    return {
      success: false,
      message: 'Invalid or unauthorized URL'
    };
  }
  
  // Additional runtime check
  const url = new URL(request.input('target_url'));
  const allowedDomains = ['example.com', 'yourservice.com'];
  if (!allowedDomains.includes(url.hostname)) {
    throw new Error('URL not in allowlist');
  }
  
  const response = await Http.get(request.input('target_url'));
  return response.body();
}

For Adonisjs applications that must make outbound requests to various domains, implement a domain allowlist with configurable exceptions:

class SafeHttpClient {
  constructor() {
    this.allowedDomains = Config.get('security.allowed_domains', []);
    this.blockedPatterns = Config.get('security.blocked_patterns', []);
  }
  
  async safeGet(url) {
    const parsedUrl = new URL(url);
    
    // Check allowlist
    if (this.allowedDomains.length > 0 && 
        !this.allowedDomains.includes(parsedUrl.hostname)) {
      throw new Error(`Domain ${parsedUrl.hostname} not allowed`);
    }
    
    // Check blocked patterns (private IPs, localhost, etc.)
    const blockedPatterns = [
      /^localhost$/, 
      /^127(?:\.[0-9]+){0,2}$/, 
      /^(10|172\.(1[6-9]|2[0-9]|3[0-1])|192\.168)\./,
      /^169\.254\.169\.254$/,
      /^0\.0\.0\.0$/
    ];
    
    if (this.blockedPatterns.length > 0) {
      const blocked = this.blockedPatterns.some(pattern => 
        pattern.test(parsedUrl.hostname)
      );
      if (blocked) {
        throw new Error('Blocked URL pattern detected');
      }
    }
    
    // Use Adonisjs HTTP client with timeout
    const response = await Http.get(url, {
      timeout: 5000, // 5 second timeout
      headers: {
        'User-Agent': 'SafeHttpClient/1.0'
      }
    });
    
    return response.body();
  }
}

Adonisjs middleware can enforce SSRF protection globally:

class SSRFProtection {
  async handle({ request, response }, next) {
    const urlParams = ['url', 'callback', 'redirect', 'target', 'file_url'];
    
    for (const param of urlParams) {
      const value = request.input(param);
      if (value && typeof value === 'string') {
        try {
          const url = new URL(value);
          if (this.isInternalNetwork(url)) {
            return response.status(400).json({
              error: 'URL points to internal network'
            });
          }
        } catch (error) {
          // Invalid URL, continue
        }
      }
    }
    
    await next();
  }
  
  isInternalNetwork(url) {
    const privateIPRanges = [
      /^127(?:\.[0-9]+){0,2}$/,
      /^(10|172\.(1[6-9]|2[0-9]|3[0-1])|192\.168)\./,
      /^169\.254\.169\.254$/,
      /^0\.0\.0\.0$/
    ];
    
    return privateIPRanges.some(pattern => pattern.test(url.hostname));
  }
}

Register this middleware in start/kernel.js:

const globalMiddleware = [
  'Adonis/Middleware/SSRProtection'
];

For Adonisjs applications using external service integrations, create a dedicated service layer with built-in SSRF protection:

class ExternalServiceManager {
  constructor() {
    this.whitelistedServices = new Set([
      'api.example.com',
      'service.yoursite.com',
      'cdn.provider.net'
    ]);
  }
  
  async callService(endpoint, data = {}) {
    const baseUrl = Config.get('services.external.base_url');
    const fullUrl = `${baseUrl}${endpoint}`;
    
    const url = new URL(fullUrl);
    if (!this.whitelistedServices.has(url.hostname)) {
      throw new Error(`Service ${url.hostname} not authorized`);
    }
    
    try {
      const response = await Http.post(fullUrl, data, {
        timeout: 10000,
        headers: {
          'Content-Type': 'application/json',
          'Authorization': `Bearer ${Config.get('services.external.token')}`
        }
      });
      
      return response.body();
    } catch (error) {
      // Log without exposing sensitive data
      Logger.warn(`External service call failed: ${error.message}`);
      throw new Error('Service temporarily unavailable');
    }
  }
}

Finally, implement comprehensive logging and monitoring for outbound requests in your Adonisjs application to detect suspicious patterns:

class RequestLogger {
  async handle({ request }, next) {
    const startTime = Date.now();
    await next();
    
    const responseTime = Date.now() - startTime;
    const url = request.url();
    
    // Log external requests for audit
    if (url.startsWith('/api/external') || url.includes('callback')) {
      Logger.info(`External request: ${url} - ${responseTime}ms`);
    }
  }
}

Related CWEs: ssrf

CWE IDNameSeverity
CWE-918Server-Side Request Forgery (SSRF) CRITICAL
CWE-441Unintended Proxy or Intermediary (Confused Deputy) HIGH

Frequently Asked Questions

How does SSRF differ from other API vulnerabilities in Adonisjs?
SSRF specifically involves the server making outbound requests to attacker-controlled destinations, unlike injection attacks which target input processing or authentication bypasses. In Adonisjs, SSRF often occurs through HTTP client usage patterns where user input determines the request destination. The key distinction is that SSRF allows attackers to leverage your server's network position to access internal resources they couldn't reach directly.
Can middleBrick detect SSRF in Adonisjs applications without source code access?
Yes, middleBrick's black-box scanning approach tests the actual runtime behavior of your Adonisjs API endpoints. It submits test payloads containing URLs pointing to internal networks, cloud metadata services, and common service ports. The scanner analyzes responses to detect SSRF vulnerabilities without needing your source code, making it ideal for testing production APIs or third-party services.