From 22ddda712e482e0d1ac30ea55556addd26edb5b9 Mon Sep 17 00:00:00 2001 From: Patrick Date: Mon, 18 May 2026 16:05:41 -0700 Subject: [PATCH] fix(sast): NoSQL/server-side JS injection via $where with unsanitized `threshold` query parameter. The previous code built a MongoDB `$where` clause by interpolating the raw `threshold` query parameter directly into a JavaScript string evaluated server-side by MongoDB. An attacker could inject arbitrary JS (e.g. `0';while(true){}'` for a DoS, or `1'; return 1 == '1` to bypass filtering and exfiltrate all allocations), since the value was wrapped only in single quotes with no validation or escaping. The fix removes `$where` entirely and replaces it with a standard, safely-typed MongoDB query: --- app/data/allocations-dao.js | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/app/data/allocations-dao.js b/app/data/allocations-dao.js index 24d4718c4a..c4bb00d9d4 100644 --- a/app/data/allocations-dao.js +++ b/app/data/allocations-dao.js @@ -60,23 +60,19 @@ const AllocationsDAO = function(db){ const searchCriteria = () => { if (threshold) { - /* - // Fix for A1 - 2 NoSQL Injection - escape the threshold parameter properly - // Fix this NoSQL Injection which doesn't sanitze the input parameter 'threshold' and allows attackers - // to inject arbitrary javascript code into the NoSQL query: - // 1. 0';while(true){}' - // 2. 1'; return 1 == '1 - // Also implement fix in allocations.html for UX. + // Fix for A1 - 2 NoSQL Injection - validate and coerce the threshold to a + // safe integer before using it in the query. Avoid using $where with + // unsanitized user input, which would allow server-side JS injection + // (e.g. "0';while(true){}'" or "1'; return 1 == '1"). const parsedThreshold = parseInt(threshold, 10); - - if (parsedThreshold >= 0 && parsedThreshold <= 99) { - return {$where: `this.userId == ${parsedUserId} && this.stocks > ${parsedThreshold}`}; + + if (Number.isInteger(parsedThreshold) && parsedThreshold >= 0 && parsedThreshold <= 99) { + return { + userId: parsedUserId, + stocks: { $gt: parsedThreshold } + }; } - throw `The user supplied threshold: ${parsedThreshold} was not valid.`; - */ - return { - $where: `this.userId == ${parsedUserId} && this.stocks > '${threshold}'` - }; + throw `The user supplied threshold: ${threshold} was not valid.`; } return { userId: parsedUserId