HIGH ssrfbasic auth

Ssrf with Basic Auth

How SSRF Manifests in Basic Auth

Server‑Side Request Forgery (SSRF) occurs when an attacker can cause an application to make an HTTP request to an unintended destination. When the vulnerable code uses HTTP Basic Authentication for the outbound request, the attack surface expands in two ways:

  • Credential leakage – If the attacker can control the target URL, they can point the request at an external server they control. The application will attach the Basic Auth header (username:password, base64‑encoded) to that request, exposing credentials.
  • Internal service probing – The attacker can target internal IP addresses, cloud metadata services, or admin interfaces that are only reachable from the application’s network. Because the request already carries valid Basic Auth credentials, any internal service that also trusts those credentials may be accessed without further authentication.

Typical vulnerable patterns look like this:

// Node.js/Express example (vulnerable)
app.get('/fetch', (req, res) => {
  const target = req.query.url; // user‑controlled
  axios.get(target, {
    auth: { username: process.env.API_USER, password: process.env.API_PASS }
  })
    .then(r => res.send(r.data))
    .catch(e => res.status(500).send(e.message));
});

In the snippet above, the target value is taken straight from the query string and passed to axios.get together with static Basic Auth credentials. An attacker can supply http://169.254.169.254/latest/meta-data/ (AWS IMDS) or http://internal‑admin:8080/ and receive the response, while the credentials are leaked in the request headers.

Similar issues appear in Python, Java, or Go when user‑supplied URLs are combined with hard‑coded or environment‑derived Basic Auth headers.

Real‑world CVEs that illustrate SSRF combined with credential exposure include:

CVEComponentImpact
CVE-2021-3129Microsoft Exchange ServerSSRF via crafted URLs allowed attackers to retrieve internal data and potentially leak NTLM hashes.
CVE-2020-14882Oracle WebLogic ServerUnauthenticated SSRF leading to remote code execution; Basic Auth credentials could be reused in subsequent requests.
CVE-2022-22965Spring Framework (Spring4Shell)Although primarily a remote code execution flaw, the exploit chain often begins with an SSRF that leaks internal service tokens.

Understanding these patterns helps developers spot where Basic Auth is being attached to outbound HTTP calls that incorporate user input.

Basic Auth‑Specific Detection

Detecting SSRF in endpoints that use Basic Auth requires looking for:

  • User‑controlled parameters that are later used as URLs, URIs, or hostnames in outbound HTTP calls.
  • The presence of Basic Auth header construction (e.g., Authorization: Basic <base64>) attached to those outbound calls.
  • Missing validation or allow‑listing of the target URL.

middleBrick’s unauthenticated black‑box scan includes an SSRF check that probes the attack surface without needing credentials. When you submit a URL, the scanner:

  1. Identifies all query string, JSON body, and header parameters that influence outbound requests (by observing variations in responses).
  2. Attempts to inject common SSRF payloads (e.g., http://127.0.0.1, file:///etc/passwd, cloud metadata endpoints) while monitoring for changes in response timing, status codes, or content that indicate a successful request.
  3. Checks whether the request includes an Authorization header with a Basic token. If the header is present and the scanner can detect a change in the outbound request (via side‑channel clues such as response differences), it flags the finding as “SSRF with Basic Auth credential exposure”.

You can reproduce the detection locally with the middleBrick CLI:

# Install the CLI (npm)
npm i -g middlebrick

# Scan an endpoint that takes a ?url= parameter
middlebrick scan https://api.example.com/fetch?url=http://safe.example.com

The output will include a section like:

SSRF (API8:2023) – HIGH
- Parameter: url
- Detected Basic Auth header in outbound request
- Evidence: Response time changed when payload pointed to 127.0.0.1:80
- Remediation: Validate and allow‑list URLs; strip credentials from outbound calls to untrusted hosts.

Because middleBrick does not need any agents, configuration, or credentials, it can be run against staging or production APIs as part of a CI pipeline (see the GitHub Action) to catch these issues before they reach users.

Basic Auth‑Specific Remediation

The fix focuses on two goals: preventing unauthorized outbound requests and ensuring that Basic Auth credentials are never sent to unintended destinations.

1. Input validation and allow‑listing

Never trust a raw user‑supplied URL. Parse it, verify the scheme, host, and port, and compare against a strict allow‑list of domains that the application is permitted to call.

// Node.js/Express – fixed version
const { URL } = require('url');
const ALLOWED_HOSTS = new Set(['api.internal.com', 'data.partner.org']);

app.get('/fetch', (req, res) => {
  let target;
  try {
    target = new URL(req.query.url);
  } catch (_) {
    return res.status(400).send('Invalid URL');
  }
  if (!ALLOWED_HOSTS.has(target.hostname)) {
    return res.status(403).send('Host not allowed');
  }
  // Optional: enforce scheme
  if (!['http:', 'https:'].includes(target.protocol)) {
    return res.status(400).send('Only HTTP/HTTPS allowed');
  }

  axios.get(target.toString(), {
    auth: { username: process.env.API_USER, password: process.env.API_PASS }
  })
    .then(r => res.send(r.data))
    .catch(e => res.status(500).send(e.message));
});

2. Decouple credentials from user‑driven calls

If the outbound request does not actually need the user’s Basic Auth credentials (e.g., the call is to a public API), remove the auth header entirely. When credentials are required, consider using a dedicated service account with minimal privileges and store it in a secret manager; never embed it in code that constructs URLs from untrusted input.

# Python/requests – fixed version
import re
from urllib.parse import urlparse

ALLOWED = {'api.internal.com', 'data.partner.org'}

def safe_fetch(user_url):
    try:
        parsed = urlparse(user_url)
    except ValueError:
        raise ValueError('Invalid URL')
    if parsed.hostname not in ALLOWED:
        raise ValueError('Host not allowed')
    if parsed.scheme not in ('http', 'https'):
        raise ValueError('Unsupported scheme')

    # Only attach Basic Auth if the host is trusted
    headers = {}
    if parsed.hostname in ALLOWED:
        import base64
        token = base64.b64encode(f"{API_USER}:{API_PASS}".encode()).decode()
        headers['Authorization'] = f'Basic {token}'

    resp = requests.get(user_url, headers=headers, timeout=5)
    resp.raise_for_status()
    return resp.text

3. Network‑level controls

Even with good application logic, enforce egress filtering (security groups, firewall rules, or service mesh policies) that only allow outbound traffic to approved IP ranges. This provides defense‑in‑depth: if a malicious URL slips through, the network will block the request.

By combining strict input validation, limiting where Basic Auth credentials are attached, and enforcing network segmentation, you eliminate the SSRF pathways that Basic Auth can expose.

Related CWEs: ssrf

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

Frequently Asked Questions

Does middleBrick need the API’s Basic Auth credentials to test for SSRF?
No. middleBrick performs unauthenticated black‑box scanning. It detects SSRF by observing how the target API responds to injected URLs and by checking whether an Authorization: Basic header is present in the outbound request, without requiring any credentials from you.
If I fix the SSRF issue, will my API’s Basic Auth authentication for legitimate clients be affected?
Fixing SSRF only changes how your API makes outbound requests. It does not alter the way clients authenticate to your API (e.g., via the Authorization header they send). Legitimate client Basic Auth flows remain unchanged.