contrib.nodejsscan.xss_node.express_xss

profile photo of returntocorpreturntocorp
Author
99
Download Count*
License

Untrusted User Input in Response will result in Reflected Cross Site Scripting Vulnerability.

Run Locally

Run in CI

Defintion

rules:
  - id: express_xss
    patterns:
      - pattern-either:
          - pattern-inside: function ($REQ, $RES, ...) {...}
          - pattern-inside: function $FUNC($REQ, $RES, ...) {...}
          - pattern-inside: $X = function $FUNC($REQ, $RES, ...) {...}
          - pattern-inside: var $X = function $FUNC($REQ, $RES, ...) {...};
          - pattern-inside: $APP.$METHOD(..., function $FUNC($REQ, $RES, ...) {...})
      - pattern-either:
          - pattern: |
              $RES.write(..., <... $REQ.$QUERY ...>, ...);
          - pattern: |
              $RES.write(..., <... $REQ.$QUERY.$FOO ...>, ...);
          - pattern: |
              $RES.send(..., <... $REQ.$QUERY ...>, ...);
          - pattern: |
              $RES.send(..., <... $REQ.$QUERY.$FOO ...>, ...);
          - pattern: |
              $LOCALVAR = <... $REQ.$QUERY ...>;
              ...
              $RES.write(..., <... $LOCALVAR ...>, ...);
          - pattern: |
              $LOCALVAR = <... $REQ.$QUERY.$FOO ...>;
              ...
              $RES.write(..., <... $LOCALVAR ...>, ...);
          - pattern: |
              $LOCALVAR = <... $REQ.$QUERY.$VAR ...>;
              ...
              $RES.send(..., <... $LOCALVAR ...>, ...);
          - pattern: |
              $LOCALVAR = <... $REQ.$QUERY ...>;
              ...
              $RES.send(..., <... $LOCALVAR ...>, ...);
          - pattern: |
              var {$LOCALVAR} = <... $REQ.$QUERY.$FOO ...>;
              ...
              $RES.write(..., <... $LOCALVAR ...>, ...);
          - pattern: |
              var {$LOCALVAR} = <... $REQ.$QUERY.$VAR ...>;
              ...
              $RES.send(..., <... $LOCALVAR ...>, ...);
          - pattern: |
              var {$LOCALVAR} = <... $REQ.$QUERY ...>;
              ...
              $RES.send(..., <... $LOCALVAR ...>, ...);
          - pattern: |
              $LOCALVAR = {$KEY: <... $REQ.$QUERY ...>};
              ...
              $RES.write(..., <... $LOCALVAR ...>, ...);
          - pattern: |
              $LOCALVAR =  {$KEY: <... $REQ.$QUERY.$FOO ...>};
              ...
              $RES.write(..., <... $LOCALVAR ...>, ...);
          - pattern: |
              $LOCALVAR = {$KEY: <... $REQ.$QUERY.$VAR ...>};
              ...
              $RES.send(..., <... $LOCALVAR ...>, ...);
          - pattern: |
              $LOCALVAR =  {$KEY: <... $REQ.$QUERY ...>};
              ...
              $RES.send(..., <... $LOCALVAR ...>, ...);
          - pattern: |
              $LOCALVAR.push(<... $REQ.$QUERY ...>);
              ...
              $RES.write(..., <... $LOCALVAR ...>, ...);
          - pattern: |
              $LOCALVAR.push(<... $REQ.$QUERY.$FOO ...>);
              ...
              $RES.write(..., <... $LOCALVAR ...>, ...);
          - pattern: |
              $LOCALVAR.push(<... $REQ.$QUERY.$VAR ...>);
              ...
              $RES.send(..., <... $LOCALVAR ...>, ...);
          - pattern: |
              $LOCALVAR.push(<... $REQ.$QUERY ...>);
              ...
              $RES.send(..., <... $LOCALVAR ...>, ...);
          - pattern: |
              $LOCALVAR = <... $REQ.$QUERY ...>;
              ...
              $ARR.push(<... $LOCALVAR ...>);
              ...
              $RES.write(..., <... $ARR ...>, ...);
          - pattern: |
              $LOCALVAR = <... $REQ.$QUERY.$FOO ...>;
              ...
              $ARR.push(<... $LOCALVAR ...>);
              ...
              $RES.write(..., <... $ARR ...>, ...);
          - pattern: |
              $LOCALVAR = <... $REQ.$QUERY.$VAR ...>;
              ...
              $ARR.push(<... $LOCALVAR ...>);
              ...
              $RES.send(..., <... $ARR ...>, ...);
          - pattern: |
              $LOCALVAR = <... $REQ.$QUERY ...>;
              ...
              $ARR.push(<... $LOCALVAR ...>);
              ...
              $RES.send(..., <... $ARR ...>, ...);
          - pattern: |
              $LOCALVAR = <... $REQ.$QUERY ...>;
              ...
              $OUT = <... $LOCALVAR ...>;
              ...
              $RES.write(..., <... $OUT ...>, ...);
          - pattern: |
              $LOCALVAR = <... $REQ.$QUERY.$FOO ...>;
              ...
              $OUT = <... $LOCALVAR ...>;
              ...
              $RES.write(..., <... $OUT ...>, ...);
          - pattern: |
              $LOCALVAR = <... $REQ.$QUERY.$VAR ...>;
              ...
              $OUT = <... $LOCALVAR ...>;
              ...
              $RES.send(..., <... $OUT ...>, ...);
          - pattern: |
              $LOCALVAR = <... $REQ.$QUERY ...>;
              ...
              $OUT = <... $LOCALVAR ...>;
              ...
              $RES.send(..., <... $OUT ...>, ...);
    message: Untrusted User Input in Response will result in Reflected Cross Site
      Scripting Vulnerability.
    languages:
      - javascript
    severity: ERROR
    metadata:
      owasp: A01:2017 - Injection
      cwe: "CWE-79: Improper Neutralization of Input During Web Page Generation
        ('Cross-site Scripting')"
      category: security
      technology:
        - node.js
        - express
      license: Commons Clause License Condition v1.0[LGPL-2.1-only]

Examples

xss_node.js


const express = require('express')
const router = express.Router()

router.get('/greeting', (req, res) => {
    // ruleid:express_xss
    const { name } = req.query;
    res.send('<h1> Hello :' + name + "</h1>")
})

//template handle escaping
router.get('/greet-template', (req, res) => {
    name = req.query.name
    res.render('index', { user_name: name });
})

module.exports = router


app.get('/', function (req, res) {
    // ruleid:express_xss
    var user = req.query.name;

    msg = "Hi " + user
    res.send('Response</br>' + msg);
});


var msg = '';
app.get('/3', function (req, res) {
    // ruleid:express_xss
    var user = req.query.name;

    msg = "Hi " + user
    res.send('Response</br>' + msg);
});

app.get('/2', function (req, res) {
    // ruleid:express_xss
    var user = { user: req.query.name };
    res.send('Response</br>' + user.name);
});

app.get('/1', function (req, res) {
    // ruleid:express_xss
    var user = req.query.name;
    var msg = [];
    msg.push(user);
    res.send('Response</br>' + msg[0]);
});

app.get('/4', function (req, res) {
    var user = req.query.name;
    var header = "<html>";
    var msg = 'Hi ' + user;
    var footer = "</html>";
    var output = header + msg + footer;
    res.send(output);
});





var express = require('express');
var app = express();
app.get('/', function (req, res) {
    // ruleid:express_xss
    var resp = req.query.name;
    res.send('Response</br>' + resp);
});
app.get('/3', function (req, res) {
    // ruleid:express_xss
    var resp = req.query.name;
    res.write('Response</br>' + resp);
});

app.get('/3', function (req, res) {
    // ruleid:express_xss
    var resp = req.foo;
    var x = 1;
    res.write('Response</br>' + resp);
});

app.get('/xss', function (req, res) {
    // ruleid:express_xss
    var html = "ASadad" + req.query.name + "Asdadads"
    res.write('Response</br>' + html);
});
app.get('/xss', function (req, res) {
    // ruleid:express_xss
    res.write('Response</br>' + req.query('doo'));
});
app.get('/xss', function (req, res) {
    // ruleid:express_xss
    res.write('Response</br>' + req.query.name);
});

app.get('/noxss', function (req, res) {
    var resp = req.query.name;
    res.write('Response</br>');
});

app.get('/noxs2s', function (req, res) {
    var resp = req.query.name;
    res.write('Response</br>' + foo);
});

app.get('/xss', function (req, res) {
    // ruleid:express_xss
    var resp = req.query.name;
    var html = "ASadad" + resp + "Asdadads"
    res.write('Response</br>' + html);
});
app.listen(8000);