SSRF

SSRF in i18next-http-middleware on Node.js (Express) [CVE-2026-42353]

[Fixed month year] Updated CVE-2026-42353

Overview

SSRF and path traversal risks in Node.js (Express) apps can arise when user-controlled values are passed directly to resource-loading backends. CVE-2026-42353 describes a vulnerability in i18next-http-middleware where, before version 3.9.3, the middleware forwards user-provided lng (languages) and ns (namespaces) from getResourcesHandler straight into i18next.services.backendConnector.load(languages, namespaces, …) without sanitization. Depending on the configured backend, these unvalidated path segments can be exploited to traverse the file system or make unintended server requests (SSRF), leading to data exposure, internal service access, or remote resource fetches. The issue is categorized under CWE-22 (Path Traversal) and CWE-918 (Server-Side Request Forgery) and was patched in 3.9.3. CWE-22 applies when attackers manipulate file paths, while CWE-918 covers scenarios where servers fetch resources based on user input. In real Express setups, this class of vulnerability can manifest whenever routes support dynamic resource loading via external backends using user-supplied identifiers. In practice, an attacker could craft requests that cause the backend loader to interpret crafted language/namespace inputs as paths or URLs pointing to internal services, files, or internal endpoints. If the backend fetches resources over the filesystem or network using those inputs, sensitive internal data or services could be exposed, and internal network topology may be probed. This highlights the risk of trusting user input in resource loading flows and the importance of validating or constraining inputs before invoking backend loaders. Remediation focuses on upgrading to i18next-http-middleware >= 3.9.3, which includes the patch, and applying input validation or whitelisting as a defense-in-depth measure. In addition to the upgrade, enforce strict validation of lng and ns, or use a allowlist of supported languages and namespaces to ensure only intended resources are loaded. After upgrading, re-audit dependencies and verify through functional tests that the middleware no longer accepts arbitrary paths or external references from user input.

Affected Versions

< 3.9.3

Code Fix Example

Node.js (Express) API Security Remediation
/* Vulnerable pattern (unvalidated user input passed to backend loader) */
const express = require('express');
const i18next = require('i18next');
const i18nextMiddleware = require('i18next-http-middleware');
const backend = require('i18next-fs-backend');

const app = express();

// Initialize i18next (simplified for illustration)
i18next.use(backend).init({
  lng: 'en',
  ns: ['translation'],
  fallbackLng: 'en',
  preload: ['en'],
  backend: { loadPath: './locales/{{lng}}/{{ns}}.json' }
});
app.use(i18nextMiddleware.handle(i18next));

// Vulnerable endpoint: user-controlled lng and ns are passed directly to the backend loader
app.get('/locales', (req, res) => {
  const languages = req.query.lng; // user-controlled input
  const namespaces = req.query.ns; // user-controlled input

  i18next.services.backendConnector.load(languages, namespaces, (err, data) => {
    if (err) return res.status(500).send(err.message);
    res.json(data);
  });
});

/* Fixed pattern (upgrade to 3.9.3+ and sanitize inputs) */
const ALLOWED_LANGS = ['en', 'de', 'fr', 'es'];
const ALLOWED_NS = ['translation', 'common'];

const sanitizeArrayParam = (param, allowed) => {
  let arr = [];
  if (Array.isArray(param)) arr = param;
  else if (typeof param === 'string') arr = param.split(',').map(p => p.trim()).filter(p => p);
  return Array.from(new Set(arr.filter(v => allowed.includes(v))));
};

app.get('/locales-fixed', (req, res) => {
  const languages = sanitizeArrayParam(req.query.lng, ALLOWED_LANGS);
  const namespaces = sanitizeArrayParam(req.query.ns, ALLOWED_NS);

  i18next.services.backendConnector.load(languages, namespaces, (err, data) => {
    if (err) return res.status(500).send(err.message);
    res.json(data);
  });
});

app.listen(3000, () => console.log('Server running on port 3000'));

CVE References

Choose which optional cookies to allow. You can change this any time.