The world of JavaScript doesn’t just revolve around browsers. Many projects use JavaScript engines as embedded runtimes—often in devices and applications far removed from the web. Artifex MuJS is one such engine—a lightweight, embeddable JavaScript interpreter used in various PDF applications. In late 2022, a dangerous vulnerability was discovered in MuJS: CVE-2022-44789. This post will break down how this bug happened, what went wrong, and how attackers could use it to run their own code on your system. If you use any software embedding MuJS, keep reading.
What is MuJS?
MuJS is a C-based, minimal JavaScript engine designed for easy integration. Artifex, the company behind MuPDF, relies on MuJS to deliver scripting support in its products. While designed for sandboxing, vulnerabilities in such engines can have dramatic consequences.
Impact: Remote Code Execution (RCE) via a specially crafted JavaScript file
References:
- CVE entry on NIST
- Upstream MuJS commit
Explaining the Bug
MuJS’s object property handling is implemented in C. The vulnerable function, O_getOwnPropertyDescriptor(), is responsible for looking up object properties by name and retrieving their descriptors. A logical error meant that under certain circumstances, a JavaScript file could trick the interpreter into *accessing freed memory*—opening the door for an attacker to control what MuJS does next.
Here’s a simplified example of similar code vulnerable to use-after-free
static js_Property *O_getOwnPropertyDescriptor(js_State *J, js_Object *obj, const char *name) {
for (int i = ; i < obj->count; ++i) {
if (strcmp(obj->properties[i].name, name) == ) {
// Problem: If a getter or setter called here deletes or reallocates properties,
// obj->properties may now point to freed memory!
return &obj->properties[i];
}
}
return NULL;
}
If the property’s getter/setter or other code path *removes or alters* the property list while this lookup is in progress (possible in a script due to re-entrancy), MuJS could end up reading from—or writing to—memory that’s already been freed or repurposed. A malicious payload could exploit this window for memory corruption.
Step 1: Crafting the Malicious JS
An attacker can write a JavaScript file which, through complex property access patterns (like side effectful getters or setters), manipulates object properties while MuJS is inside O_getOwnPropertyDescriptor(). By freeing or altering memory at just the right time, the attacker gains an opportunity to overwrite dangerous targets.
Step 2: Gaining Code Execution
With careful memory manipulation (for example, reallocating freed memory with attacker-controlled data), an attacker may be able to:
Pivot execution to a controlled location (e.g., shellcode, or ROP chain)
Because MuJS is often used for *remotely loaded scripts* (like in PDF readers or other automation), this attack could happen just by opening or processing a crafted file.
Here’s how an attack might look in JavaScript
let victim = {};
Object.defineProperty(victim, "danger", {
get: function() {
// While property is being examined, trigger logic to delete/redefine properties
// This causes MuJS to reallocate or free the properties array
for (let k in victim) { delete victim[k]; }
Object.defineProperty(victim, "evil", { value: "I control memory!" });
return 42;
}
});
victim.danger;
Note: The actual exploit would be far more complicated, using heap spraying, specific allocation patterns, and likely reverse-engineered knowledge of MuJS's heap.
Patch & Fix References
The root cause was patched in commit 5b17313, by making object property lookups *safe against re-entrancy* and ensuring that internal pointers remain valid across accesses.
Always update to at least MuJS v1.3.2 to remain safe from this issue.
Update MuJS immediately wherever it’s embedded.
- Audit any application which lets untrusted parties supply JavaScript code. This includes PDF viewers, document workflow tools, and automation suites.
Final Words
This bug, CVE-2022-44789, serves as a sharp reminder: “trusted” scripting engines can be a loaded gun if not carefully maintained. Invisible-to-the-eye logical issues can allow attackers to achieve remote code execution, especially when code is loaded from files or network.
If you’re a developer, don’t delay—check your dependencies. If you’re a user, update software that could possibly parse files containing embedded JavaScript.
More details can be found at:
- NIST NVD Entry
- MuJS Source Patch
Stay secure & stay updated!
*Written exclusively for you by an AI security enthusiast. Please research and patch responsibly!*
Timeline
Published on: 11/23/2022 21:15:00 UTC
Last modified on: 02/01/2023 15:59:00 UTC