← Back to blog
·8 min read

Axios Security Vulnerabilities: What They Are & How to Fix Them

AxiosSecurityNode.jsNext.jsVulnerabilitiesWeb Security
Axios Security Vulnerabilities: What They Are & How to Fix Them

Why Axios Security Matters

Axios is the most popular HTTP client in the JavaScript ecosystem — used in millions of Node.js backends, React frontends, and Next.js apps. That popularity makes it a high-value target, and its flexibility means it's easy to misuse in ways that introduce serious vulnerabilities.

If you're building or buying code that makes HTTP requests, you need to understand these attack vectors. This guide covers the real vulnerabilities — what they are, how they're exploited, and exactly how to fix them.

Vulnerability 1: Server-Side Request Forgery (SSRF)

SSRF is the most critical Axios vulnerability in server-side code. It lets attackers make your server send requests to internal services it shouldn't be able to reach.

How it happens:

typescript
// ❌ DANGEROUS — never pass user input directly to axios
app.post('/fetch-preview', async (req, res) => {
  const { url } = req.body;
  const response = await axios.get(url); // attacker controls this
  res.json(response.data);
});

An attacker sends url: "http://169.254.169.254/latest/meta-data/" — the AWS metadata endpoint. Your server fetches it and returns cloud credentials, IAM roles, or environment variables.

Fix — validate and restrict URLs before fetching:

typescript
import { URL } from 'url';

const BLOCKED_HOSTS = ['localhost', '127.0.0.1', '0.0.0.0', '169.254.169.254'];
const BLOCKED_RANGES = [/^10\./, /^192\.168\./, /^172\.(1[6-9]|2\d|3[01])\./];

function isSafeUrl(rawUrl: string): boolean {
  try {
    const parsed = new URL(rawUrl);
    if (!['http:', 'https:'].includes(parsed.protocol)) return false;
    const host = parsed.hostname.toLowerCase();
    if (BLOCKED_HOSTS.includes(host)) return false;
    if (BLOCKED_RANGES.some(r => r.test(host))) return false;
    return true;
  } catch {
    return false;
  }
}

app.post('/fetch-preview', async (req, res) => {
  const { url } = req.body;
  if (!isSafeUrl(url)) return res.status(400).json({ error: 'Invalid URL' });
  const response = await axios.get(url, { maxRedirects: 3 });
  res.json(response.data);
});

Also set maxRedirects — attackers chain open redirects to bypass URL validation.

Vulnerability 2: Credential Leaks via Misconfigured Instances

Axios instances created with auth headers or API keys can accidentally send credentials to the wrong endpoints.

How it happens:

typescript
// ❌ Global instance with credentials — used everywhere
const api = axios.create({
  baseURL: 'https://api.internal.company.com',
  headers: { Authorization: `Bearer ${process.env.INTERNAL_API_KEY}` }
});

// Later in code, someone uses the same instance for an external call
await api.get('https://external-third-party.com/data');
// Your internal API key just got sent to a third party

Fix — scope instances strictly, never reuse credentialed instances for external calls:

typescript
// ✅ Separate instances per target
const internalApi = axios.create({
  baseURL: 'https://api.internal.company.com',
  headers: { Authorization: `Bearer ${process.env.INTERNAL_API_KEY}` }
});

const externalApi = axios.create({
  timeout: 5000,
});

// Interceptor to catch accidental cross-domain credential leaks
internalApi.interceptors.request.use((config) => {
  const url = new URL(config.url!, config.baseURL);
  if (!url.hostname.endsWith('.company.com')) {
    throw new Error(`Blocked: internal API client used for external host ${url.hostname}`);
  }
  return config;
});

Vulnerability 3: HTTP Header Injection

If you pass user-controlled values into request headers, attackers can inject newline characters (\r\n) to split the HTTP response and inject arbitrary headers or body content.

How it happens:

typescript
// ❌ User input directly in headers
const userLocale = req.query.locale; // attacker sends: "en\r\nX-Injected: malicious"
await axios.get('https://api.example.com/data', {
  headers: { 'Accept-Language': userLocale }
});

Fix — strip control characters from any user-supplied header values:

typescript
function sanitizeHeaderValue(value: string): string {
  return value.replace(/[\r\n\0]/g, '');
}

await axios.get('https://api.example.com/data', {
  headers: {
    'Accept-Language': sanitizeHeaderValue(req.query.locale as string)
  }
});

Modern Axios 1.x throws on headers containing \r or \n, but Axios 0.x does not — check your version.

Vulnerability 4: Prototype Pollution via Response Data

When you spread or merge Axios response data into objects without validation, attackers can pollute Object.prototype — affecting all objects in the process.

How it happens:

typescript
// ❌ Merging untrusted response data into config objects
const response = await axios.get('/api/user-config');
const config = Object.assign({}, defaultConfig, response.data);
// If response.data = { "__proto__": { "isAdmin": true } }
// every object in the app now has isAdmin = true

Fix — validate response shape with Zod before using:

typescript
import { z } from 'zod';

const UserConfigSchema = z.object({
  theme: z.enum(['light', 'dark']),
  language: z.string().max(10),
  notifications: z.boolean(),
});

const response = await axios.get('/api/user-config');
const config = UserConfigSchema.parse(response.data); // throws if shape is wrong

Vulnerability 5: No Timeout — DoS via Slow Connections

Axios has no default timeout. A slow or malicious server can hold your connection open indefinitely, exhausting your server's connection pool.

Fix — always set timeouts:

typescript
const api = axios.create({
  timeout: 5000,
  maxContentLength: 10 * 1024 * 1024, // 10MB max response
  maxBodyLength: 1 * 1024 * 1024,      // 1MB max request body
});

Vulnerability 6: Leaking Axios Errors to Clients

Axios errors contain the full request config — including URLs, headers, and auth tokens. Forwarding them directly to clients leaks internals.

How it happens:

typescript
// ❌ Raw Axios error sent to client
} catch (error) {
  res.status(500).json({ error }); // leaks config, headers, auth tokens
}

Fix — sanitize before sending:

typescript
import axios, { AxiosError } from 'axios';

} catch (error) {
  if (axios.isAxiosError(error)) {
    console.error('Axios error:', { url: error.config?.url, status: error.response?.status });
    res.status(error.response?.status ?? 500).json({
      error: 'Request failed',
      status: error.response?.status,
    });
  } else {
    res.status(500).json({ error: 'Internal server error' });
  }
}

Real CVEs to Know

CVE-2023-45857 — Axios < 1.6.0 exposed XSRF-TOKEN cookies to third-party origins when a custom xsrfHeaderName was set. Fixed in 1.6.1.

CVE-2021-3749 — Axios 0.21.1 vulnerable to ReDoS (Regular Expression Denial of Service) in URL parsing.

Check your version and update:

bash
npm list axios
npm install axios@latest
npm audit --audit-level=moderate

Security Checklist

No user-controlled URLs passed directly to axios.get/post
URL allowlist or blocklist in place for URL-accepting endpoints
maxRedirects set on requests accepting user URLs
Separate Axios instances per service (no shared credentialed instances)
Domain-validation interceptors on credentialed instances
Header values sanitized (no raw query param to header)
Response data validated with Zod or equivalent
timeout, maxContentLength, maxBodyLength set on all instances
Axios errors sanitized before sending to clients
npm audit in CI pipeline
Axios >= 1.6.1

Buying Code That Uses Axios?

Quick audit of any purchased template:

bash
# Unvalidated URL usage
grep -r "axios.get(req." src/
grep -r "axios.get(body." src/

# Missing timeouts
grep -r "axios.create({" src/ | grep -v "timeout"

# Check version
cat package.json | grep axios

Run these before deploying any third-party code to production.

Browse production-ready Next.js templates on CodeCudos or submit your own secure codebase.

Browse Quality-Scored Code

Every listing on CodeCudos is analyzed for code quality, security, and documentation. Find production-ready components, templates, and apps.

Browse Marketplace →