CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



CVE-2017-1001003

The Unicode Ghost: Breaking Math.js with Invisible Ink

Amit Schendel
Amit Schendel
Senior Security Researcher

Feb 21, 2026·6 min read·32 visits

Executive Summary (TL;DR)

A critical RCE in math.js < 3.17.0 allows attackers to execute arbitrary system code. The vulnerability exploits a disparity between how the security validator reads strings vs. how the JS engine executes them. By masking forbidden property names (like 'constructor') with Unicode escapes (e.g., 'co\u006Estructor'), attackers can bypass the sandbox and pop a shell.

Math.js, the popular extensive math library for JavaScript and Node.js, suffered from a critical sandbox escape vulnerability. By utilizing Unicode escape sequences in object property keys, attackers could bypass the library's internal security blacklist. This allowed access to the `constructor` property, enabling the execution of arbitrary JavaScript code via the `Function` constructor. Essentially, the security guard was checking ID cards for 'Admin', but let 'Adm\u0069n' walk right through the front door.

The Hook: It's Just Math, Right?

We tend to trust math. It's absolute, deterministic, and safe. When a developer imports a library like math.js to handle complex expressions or user-defined formulas, they usually assume the worst-case scenario is a division by zero or maybe a resource exhaustion loop. They rarely expect that calculating 2 + 2 could result in a reverse shell opening up on their production server.

math.js is a beast of a library. It handles matrices, big numbers, and crucially, it comes with an expression parser that allows users to define variables and functions. To support this flexibility, the library implements a custom scope—a sandbox. The goal is simple: allow the user to do math, but don't let them touch the underlying JavaScript engine's sensitive internals, specifically the Object prototype chain.

But here is the thing about JavaScript sandboxes: they are like trying to hold water in your hands. Eventually, it leaks. In CVE-2017-1001003, the leak wasn't a complex memory corruption or a race condition. It was a linguistic misunderstanding between the security guard (the validator) and the executioner (the runtime). The validator only spoke ASCII, but the runtime was fluent in Unicode.

The Flaw: A Case of Mistaken Identity

The core of the vulnerability lies in the isSafeProperty function. This function serves as the bouncer for the math.js expression evaluator. Its job is to check every property access or object definition against a blacklist of forbidden words. Naturally, this list includes the usual suspects: constructor, __proto__, prototype, and __defineGetter__. If you try to run math.eval('a.constructor'), the bouncer sees the word "constructor", panics, and throws an error. System secure. Good job, everyone.

However, the flaw is a classic example of Canonicalization Issues (CWE-20). The validator checked the raw string provided in the expression. If I type co\u006Estructor, the validator sees a string containing a backslash, a 'u', and some numbers. It compares co\u006Estructor against constructor. Strings are not equal. The bouncer waves it through.

But later down the pipeline, the JavaScript engine—which is compliant with the ECMAScript standard—looks at that same string. It sees the escape sequence \u006E and politely translates it into the character n. Suddenly, co\u006Estructor becomes constructor. The attacker has now accessed the forbidden property, effectively turning the "safe" math expression evaluator into a remote code execution engine.

The Code: The Smoking Gun

Let's look at the code responsible for this mess. The vulnerability resided in lib/expression/node/ObjectNode.js, specifically where object properties were being processed.

The Vulnerable Code:

// The naive check
if (!isSafeProperty(node.properties, key)) {
  throw new Error('No access to property "' + key + '"');
}

Here, key is the raw identifier from the parsed expression tree. It hasn't been normalized. It is exactly what the user typed. If the user types Unicode escapes, key contains them literally.

The Fix (Commit a60f3c8):

The maintainer, Jos de Jong, realized that to validate input correctly, you must view the input exactly as the interpreter will view it. The fix forces the key to be "stringified" and then parsed back, which forces the resolution of Unicode escapes before the security check happens.

// The robust check
var stringifiedKey = stringify(key);
var parsedKey = JSON.parse(stringifiedKey);
 
// Now we check the resolved version of the key
if (!isSafeProperty(node.properties, parsedKey)) {
  throw new Error('No access to property "' + parsedKey + '"');
}

By round-tripping the key through JSON.parse(stringify(...)), co\u006Estructor is transformed into constructor before it hits isSafeProperty. The bouncer now recognizes the disguise.

The Exploit: From Math to Shell

Exploiting this is trivially elegant. We don't need buffer overflows or heap spraying. We just need to ask JavaScript to give us the Function constructor.

In JavaScript, if you have an object obj, obj.constructor returns the function that created it (usually Object). obj.constructor.constructor returns the Function constructor. The Function constructor is effectively eval()—it takes a string of code and creates a function that executes it.

The Attack Chain:

  1. Bypass the Filter: Create an object property pointing to constructor, but spell it with Unicode: {"co\u006Estructor": 1}.
  2. Climb the Prototype Chain: Access the value of that property to get the Object constructor.
  3. Get the God Function: Access the .constructor of the Object constructor to get the global Function constructor.
  4. Execute: Pass a payload string to generate a malicious function and immediately invoke it.

The Payload:

// This looks like a math expression, but it executes 'kill'
math.eval(`
  a = {"co\\u006Estructor": 1};
  a.constructor.constructor("return process.kill(process.pid)")()
`);

In a real-world scenario, instead of killing the process, an attacker would use child_process (if available in the context) or standard filesystem APIs to exfiltrate environment variables (AWS keys, DB creds) or establish a reverse shell.

The Impact: Why You Should Panic

This vulnerability scored a CVSS 9.8 for a reason. It is unauthenticated, requires no user interaction (other than the system processing the input), and results in total compromise of the application's confidentiality, integrity, and availability.

Consider where math.js is used. It is often embedded in SaaS platforms to allow users to define custom pricing formulas, financial models, or scientific calculations. These features are by definition "remote code execution as a feature," restricted only by the sandbox. CVE-2017-1001003 dissolves that sandbox entirely.

If your backend runs this code, the attacker runs as the user of your Node.js process. They can read your .env files, dump your database, or use your server as part of a botnet. The "math" library becomes the foothold for a full infrastructure compromise.

The Fix: Closing the Loophole

The remediation is straightforward: Update math.js to version 3.17.0 or later immediately.

If you cannot update for some reason (legacy dependency hell), you have to implement a sanitizer before the input reaches math.eval. A rough mitigation would be to reject any input containing the \u sequence, although this might break legitimate mathematical notation or string usage depending on your use case.

> [!NOTE] > Developer Takeaway: When validating input, always validate the canonical form of the data. If your system transforms data (URL decoding, Unicode normalization, XML parsing) after your security check, you are vulnerable. Always normalize first, then validate.

Official Patches

math.jsCommit fixing the Unicode normalization bypass

Fix Analysis (1)

Technical Appendix

CVSS Score
9.8/ 10
CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
EPSS Probability
0.49%
Top 35% most exploited

Affected Systems

math.js < 3.17.0Node.js applications using vulnerable math.js for user input evaluationFront-end applications evaluating user-defined math expressions

Affected Versions Detail

Product
Affected Versions
Fixed Version
math.js
josdejong
< 3.17.03.17.0
AttributeDetail
CWE IDCWE-20 / CWE-88
CVSS v3.09.8 (Critical)
Attack VectorNetwork (Remote)
Exploit StatusPoC Available
EPSS Score0.49%
ImpactArbitrary Code Execution

MITRE ATT&CK Mapping

T1059.007Command and Scripting Interpreter: JavaScript
Execution
T1203Exploitation for Client Execution
Execution
CWE-20
Improper Input Validation

Known Exploits & Detection

GitHubOriginal issue report by Masato Kinugawa demonstrating the bypass.

Vulnerability Timeline

Vulnerability reported by Masato Kinugawa
2017-11-18
Patch developed and committed
2017-11-18
math.js version 3.17.0 released
2017-11-18
CVE-2017-1001003 Published
2017-11-27

References & Sources

  • [1]math.js Changelog v3.17.0
  • [2]NIST NVD Entry

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.

More Reports

•13 minutes ago•CVE-2026-88046
5.3

CVE-2026-88046: Directory Traversal and Root Confinement Escape in rclone Core Engine

CVE-2026-88046 (also tracked via GHSA-38xv-hf3p-h7mq) is a directory traversal and root confinement escape vulnerability residing in the core listing and transfer logic of rclone. Prior to version 1.75.1, raw relative parent-directory sequences returned by flat-keyspace source backends are trusted and processed without proper sanitization, enabling writes outside the designated target root or bucket.

Amit Schendel
Amit Schendel
0 views•5 min read
•about 1 hour ago•CVE-2026-88017
7.3

CVE-2026-88017: Cross-Session Authentication-Proxy Backend Confusion in rclone FTP Server

The FTP server implementation of rclone is vulnerable to a cross-session identity and credential confusion flaw when configured with an authentication proxy. Under specific multi-tenant configurations where multiple distinct sessions authenticate with the same username, a global map caches credentials globally instead of isolating them inside the session context. This allows a concurrent attacker to hijack the active session backend of a victim using the same username.

Alon Barad
Alon Barad
0 views•7 min read
•about 2 hours ago•CVE-2026-88044
9.1

CVE-2026-88044: Authentication Bypass in rclone Dynamic Server Execution via Remote Control API

An authentication bypass vulnerability exists in rclone when dynamically starting FTP, S3, or SFTP servers via the Remote Control (RC) 'serve/start' API. The server constructors incorrectly check the global process configuration rather than request-scoped options, resulting in a silent bypass of the authentication proxy and enabling unauthenticated access.

Alon Barad
Alon Barad
3 views•6 min read
•about 3 hours ago•CVE-2026-88018
9.8

CVE-2026-88018: Authentication Bypass in rclone S3 Server Component via Empty HMAC Secret

Prior to version 1.75.1, rclone's S3 server component ('rclone serve s3') contains an authentication bypass vulnerability when configured with '--auth-proxy' but without '--auth-key'. The application validates AWS Signature Version 4 (SigV4) against an empty secret key string, enabling unauthenticated remote attackers to access storage backends.

Alon Barad
Alon Barad
7 views•6 min read
•about 4 hours ago•CVE-2026-88015
5.3

CVE-2026-88015: Request-Level Denial of Service via Go Slice Bounds Panic in rclone Local Backend

A request-level denial of service vulnerability exists in rclone versions prior to 1.75.1 when configured with local symlink virtualization (--links) and serving files over HTTP or WebDAV. An unauthenticated remote attacker can trigger a Go runtime slice bounds panic by sending a crafted HTTP Range request with an offset exceeding the path length of the target symlink.

Alon Barad
Alon Barad
5 views•6 min read
•about 5 hours ago•CVE-2026-88013
3.7

CVE-2026-88013: Sensitive Header Leakage via Unvalidated HTTP Redirects in rclone

rclone versions from 1.49.0 up to 1.75.1 are vulnerable to information disclosure and credential leakage. When configuring custom headers on HTTP connections, rclone fails to strip those headers when following HTTP redirects to external untrusted domains. Additionally, rclone does not prevent scheme downgrades from HTTPS to HTTP on same-host redirects, allowing sensitive standard credentials to be transmitted in cleartext.

Amit Schendel
Amit Schendel
4 views•7 min read