contrib.nodejsscan.nosql_injection.node_nosqli_js_injection

profile photo of returntocorpreturntocorp
Author
99
Download Count*
License

Untrusted user input in MongoDB $where operator can result in NoSQL JavaScript Injection.

Run Locally

Run in CI

Defintion

rules:
  - id: node_nosqli_js_injection
    patterns:
      - pattern-either:
          - pattern: |
              $OBJ.$FUNC({$where: <... $REQ.$FOO.$BAR ...>}, ...);
          - pattern: |
              $OBJ.$FUNC({$where: <... $REQ.$QUERY ...>}, ...);
          - pattern: |
              $NSQL = <... $REQ.$QUERY.$...>;
              ...
              $OBJ.$FUNC({$where: <... $NSQL ...>}, ...);
          - pattern: |
              $NSQL = <... $REQ.$QUERY ...>;
              ...
              $OBJ.$FUNC({$where: <... $NSQL ...>}, ...);
          - pattern: |
              $INP = $REQ.$FOO.$BAR;
              ...
              $QRY = {$where: <... $INP ...>};
              ...
              $OBJ.$FUNC(<... $QRY ...>, ...);
          - pattern: |
              $INP = $REQ.$FOO;
              ...
              $QRY = {$where: <... $INP ...>};
              ...
              $OBJ.$FUNC(<... $QRY ...>, ...);
          - pattern: |
              $QRY["$where"] = <... $REQ.$FOO ...>;
              ...
              $OBJ.$FUNC(<... $QRY ...>, ...);
          - pattern: |
              $QRY["$where"] = <... $REQ.$FOO.$BAR ...>;
              ...
              $OBJ.$FUNC(<... $QRY ...>, ...);
          - pattern: |
              $INP = $REQ.$FOO;
              ...
              $QRY["$where"] = <... $INP ...>;
              ...
              $OBJ.$FUNC(<... $QRY ...>, ...);
          - pattern: |
              $INP = $REQ.$FOO.$BAR;
              ...
              $QRY["$where"] = <... $INP ...>;
              ...
              $OBJ.$FUNC(<... $QRY ...>, ...);
    message: Untrusted user input in MongoDB $where operator can result in NoSQL
      JavaScript Injection.
    languages:
      - javascript
    severity: ERROR
    metadata:
      owasp: A01:2017 - Injection
      cwe: "CWE-943: Improper Neutralization of Special Elements in Data Query Logic"
      category: security
      technology:
        - node.js
        - express
      license: Commons Clause License Condition v1.0[LGPL-2.1-only]

Examples

nosql_injection.js

var MongoClient = require('mongodb').MongoClient;
// mongo js injection https://lockmedown.com/securing-node-js-mongodb-security-injection-attacks/
timelineRouter.route("/api/timeline")
    .get(async function (req, res) {
        try {
            var foo = req.foo.bar;
            const startDate = "01/01/2000";
            // ruleid:node_nosqli_js_injection
            const endDate = req.query.end;
            const query = { $where: "this.hidden == false" };

            if (startDate && endDate) {
                query["$where"] = "this.start >= new Date('" + startDate + "') && " +
                    "this.end <= new Date('" + endDate + "') &&" +
                    "this.hidden == false;";
            }

            const TimelineItem = await getTimelineItemModel();
            const timelineItems = await TimelineItem.find(query);
            console.log(colors.yellow(`# of Timeline Items retrieved: ${timelineItems.length}`));
            return res.json({ timelineItems: timelineItems });

        } catch (error) {
            res.status(500).send("There was an error retrieving timeline items.  Please try again later");
        }
    });

// https://nullsweep.com/a-nosql-injection-primer-with-mongo/
// ruleid:node_nosqli_js_injection
let username = req.query.username;
var query = { $where: `this.username == '${username}'` }
User.find(query, function (err, users) {
    if (err) {
        // Handle errors
    } else {
        res.render('userlookup', { title: 'User Lookup', users: users });
    }
});

app.post('/foo', function (req, res) {
    var query = {};
    // ruleid:node_nosqli_js_injection
    query['$where'] = `this.email == '${req.body.email}'`;
    User.find(query, function (err, data) {
        if (err) {
            res.send(err);
        } else if (data) {
            res.send('User Login Successful');
        } else {
            res.send('Wrong Username Password Combination');
        }
    })
});