Outdated Date Library Allows Attackers to Tamper with Server Files

Your application uses an outdated version of Moment.js — a popular tool for handling dates and times — that contains a known security flaw. If any part of your app lets users choose a language or locale (e.g., 'English', 'French'), an attacker could craft a malicious input to access or manipulate files on your server that they shouldn't be able to touch. This only affects server-side usage, not purely browser-based code.

Business Impact And Actions

high urgency

Business Impact

If exploited, an attacker could tamper with server-side files, potentially altering application behaviour or, in worst-case scenarios combined with file upload features, executing malicious code. Beyond the direct technical risk, running software with a publicly known vulnerability can flag your application in compliance audits (such as SOC 2 or ISO 27001 reviews) and erode customer trust if a breach occurs. Additionally, Moment.js is officially deprecated — meaning it will receive no future security fixes — making this a good opportunity to move to a maintained alternative.

What To Do

  1. Ask your developer to upgrade Moment.js to version 2.29.2 or later — this is a straightforward package update that typically takes under an hour.
  2. If an immediate upgrade isn't possible, ask your developer to ensure that any user-supplied language or locale values are validated against a fixed allowlist before being passed to Moment.js.
  3. Ask your developer to audit whether your app accepts locale input from users at all — if it doesn't, your exposure is significantly lower.
  4. Consider planning a migration away from Moment.js entirely, as it is no longer actively maintained and will not receive future security patches.

Moment.js Path Traversal via Unsanitized Locale Input (CVE-2022-24785)

high severity CVSS 7.5

Vulnerability Explanation

The `moment.locale()` function in Moment.js versions 1.0.1 through 2.29.1 passes user-supplied locale strings directly to Node.js's `require()` call without sanitization. Specifically, the internal `loadLocale()` function constructs a module path as `'./locale/' + name`, where `name` is attacker-controlled. By supplying a path traversal string such as `../../uploads/malicious`, an attacker can cause Node.js to `require()` an arbitrary file outside the intended locale directory. While `require()` expects JavaScript modules (not arbitrary files like `/etc/passwd`), this becomes a realistic code execution vector when the application also allows file uploads — an attacker can upload a `.js` file and then use the traversal to load and execute it. The vulnerability is exploitable only in server-side (Node.js/npm) contexts; browser builds are not affected.

Root Cause

The `loadLocale()` function in Moment.js directly concatenates user input into a `require()` path without validating or sanitizing the input against path traversal sequences (`../`). The fix in 2.29.2 adds a regular expression check that rejects locale strings containing path separators or traversal sequences before they reach `require()`.

Technical Impact

On a server running a vulnerable version of Moment.js where locale values are sourced from user input: an attacker can traverse the filesystem to load arbitrary JavaScript files via Node.js `require()`. If the application also has a file upload feature, this escalates to Remote Code Execution (RCE). Even without file upload, the attacker can cause unexpected module loading, application errors, or integrity violations by manipulating which locale file is loaded. CVSS 3.1 Base Score: 7.5 (AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N).

Severity Justification

Network-accessible, no authentication required, no user interaction needed. Primary impact is integrity (HIGH) with no direct confidentiality or availability impact per the official CVSS vector. Exploitability is conditional on user-controlled locale input reaching moment.locale() server-side; RCE requires an additional file upload primitive.

Affected Components

  • moment (npm) >= 1.0.1, < 2.29.2
  • Moment.js (NuGet) < 2.29.2

Remediation Steps

  1. Upgrade Moment.js to version 2.29.2 or later: `npm install moment@latest` (or pin to `^2.29.4` in package.json). Run `npm audit` afterwards to confirm the finding is resolved.
  2. If an immediate upgrade is blocked, apply the input sanitization workaround: validate any user-supplied locale string against a strict allowlist of known locale codes before passing it to `moment.locale()`. Reject any value containing `/`, `\`, or `.`.
  3. Search your codebase for all calls to `moment.locale(userInput)` or `moment(date, format, userInput)` where the locale argument originates from an HTTP request, query parameter, or any external source. These are the only vulnerable call sites.
  4. If you are on Node.js and cannot upgrade immediately, consider disabling dynamic locale switching entirely and hardcoding the locale at application startup.
  5. Long-term: plan migration away from Moment.js. It is officially in maintenance mode and will not receive new features or proactive security fixes. Recommended alternatives: Luxon (closest API parity, actively maintained), Day.js (smallest bundle, Moment-compatible API), or date-fns (tree-shakeable, functional style).

Verification Steps

  1. After upgrading, run `npm list moment` to confirm the installed version is 2.29.2 or higher.
  2. Run `npm audit` and verify CVE-2022-24785 no longer appears in the output.
  3. If you applied the allowlist workaround, test that a traversal payload is rejected: send a request with `?locale=../../etc/passwd` and confirm the application defaults to a safe locale rather than attempting to load the path.
  4. Check your `package-lock.json` or `yarn.lock` for any transitive dependencies that may still pull in an older version of moment, and update those as well.

Code Examples (javascript)

Vulnerable
// VULNERABLE: user-controlled locale passed directly to moment
app.get('/time', (req, res) => {
  const locale = req.query.locale || 'en'; // attacker controls this
  const time = moment().locale(locale).format('LLLL');
  res.send(time);
});
Fixed
// FIXED option 1: Upgrade to moment >= 2.29.2 (patch applied internally)
// npm install moment@latest

// FIXED option 2: Allowlist validation (workaround for older versions)
const ALLOWED_LOCALES = new Set(['en', 'fr', 'de', 'es', 'ja', 'zh-cn']);

app.get('/time', (req, res) => {
  const requested = req.query.locale || 'en';
  const locale = ALLOWED_LOCALES.has(requested) ? requested : 'en';
  const time = moment().locale(locale).format('LLLL');
  res.send(time);
});

Best Practices

  • Never pass user-supplied strings directly to filesystem operations, module loaders, or library functions that internally perform path resolution — always validate against an explicit allowlist first.
  • Run `npm audit` as part of your CI/CD pipeline to catch known vulnerabilities in dependencies before they reach production.
  • Prefer actively maintained libraries over deprecated ones; Moment.js is in maintenance mode and will not receive proactive security updates.
  • When accepting locale or language preferences from users, validate against the specific set of locales your application supports, not just a format check.

Found this in your infrastructure?

VulWall scans for this and dozens of other issues automatically.

Scan Your Domain Free