Skip to content

Commit

Permalink
feat(js): add mongoDB NoSQLi rule (#381)
Browse files Browse the repository at this point in the history
  • Loading branch information
elsapet authored Apr 29, 2024
1 parent 6067afe commit 9f2de22
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 0 deletions.
70 changes: 70 additions & 0 deletions rules/javascript/express/nosql_injection.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
imports:
- javascript_shared_common_external_input
patterns:
- pattern: new $<MODEL>($<...>$<INPUT>$<...>)
filters:
- variable: INPUT
detection: javascript_lang_nosql_injection_unsanitized_external_input
scope: result
- variable: MODEL
detection: javascript_lang_nosql_injection_mongo_db_model
- pattern: $<MODEL>.$<METHOD>($<...>$<INPUT>$<...>)
filters:
- variable: INPUT
detection: javascript_lang_nosql_injection_unsanitized_external_input
scope: result
- variable: MODEL
detection: javascript_lang_nosql_injection_mongo_db_model
- variable: METHOD
regex: (find|delete|update|replace|where|create|insert|map|bulk|aggregate|count).*
auxiliary:
- id: javascript_lang_nosql_injection_mongo_db_model
patterns:
- pattern: require($<MODEL_IMPORT>)
filters:
- variable: MODEL_IMPORT
string_regex: .*(db|models|data|schema|mongo).*
- id: javascript_lang_nosql_injection_unsanitized_external_input
sanitizer: javascript_lang_nosql_injection_sanitizer
patterns:
- pattern: $<UNSANITIZED_INPUT>
filters:
- variable: UNSANITIZED_INPUT
detection: javascript_shared_common_external_input
scope: cursor
- id: javascript_lang_nosql_injection_sanitizer
patterns:
- $<!>$<_>.toString()
languages:
- javascript
severity: critical
metadata:
description: Unsanitized input in NoSQL query
remediation_message: |
## Description
Including unsanitized data, such as user input or request data, or externally influenced data passed to a function, in NoSQL queries could make your application vulnerable to NoSQL injection attacks.
## Remediations
❌ Avoid raw queries, especially those that contain unsanitized input
```javascript
const User = require("../models/user")
const newUser = new User(req.body); // unsafe
```
✅ Sanitize query input wherever possible
```javascript
const User = require("../models/user");
username = req.params.username;
User.findOne({ name: username.toString() });
```
## Resources
- [OWASP nosql injection explained](https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/07-Input_Validation_Testing/05.6-Testing_for_NoSQL_Injection)
cwe_id:
- 943
id: javascript_express_nosql_injection
documentation_url: https://docs.bearer.com/reference/rules/javascript_express_nosql_injection
20 changes: 20 additions & 0 deletions tests/javascript/express/nosql_injection/test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
const {
createNewInvoker,
getEnvironment,
} = require("../../../helper.js")
const { ruleId, ruleFile, testBase } = getEnvironment(__dirname)

describe(ruleId, () => {
const invoke = createNewInvoker(ruleId, ruleFile, testBase)

test("nosql_injection", () => {
const testCase = "app.js"

const results = invoke(testCase)

expect(results).toEqual({
Missing: [],
Extra: []
})
})
})
26 changes: 26 additions & 0 deletions tests/javascript/express/nosql_injection/testdata/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
const express = require('express')
const Customer = require('../models/customer')
const User = require('db/user')

const app = express()

app.post('/bad', async (req, res, _next) => {
// bearer:expected javascript_express_nosql_injection
let user = new User(req.body)
await user.save()

let { username, password } = req.body
// bearer:expected javascript_express_nosql_injection
Customer.findOne({ username, password })
// bearer:expected javascript_express_nosql_injection
let customer = Customer.findOne({ username: req.body.username, password: req.body.password })

return res.json(user, customer)
})

app.post('/ok', async (req, res, _next) => {
let { username, password } = req.body
// toString() sanitization
let customer = Customer.findOne({ username: username.toString(), password: password.toString() })
return res.json(customer)
})

0 comments on commit 9f2de22

Please sign in to comment.