contrib.nodejsscan.host_header_injection.host_header_injection

profile photo of returntocorpreturntocorp
Author
99
Download Count*
License

Using untrusted Host header for generating dynamic URLs can result in web cache and or password reset poisoning.

Run Locally

Run in CI

Defintion

rules:
  - id: host_header_injection
    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: |
              $X = <... "=~/.*http[s]*:///" + $REQ.host ...>;
          - pattern: |
              $X = <... "=~/.*http[s]*:///" + $REQ["host"] ...>;
          - pattern: |
              $X = <... "=~/.*http[s]*:///" + $REQ("host") ...>;
          - pattern: |
              $X = { $Y: <... "=~/.*http[s]*:///" + $REQ.host ...>};
          - pattern: |
              $X = { $Y: <... "=~/.*http[s]*:///" + $REQ["host"] ...>};
          - pattern: |
              $X = { $Y: <... "=~/.*http[s]*:///" + $REQ("host") ...>};
          - pattern: |
              $Z = $REQ.host;
              ...
              $X = <... "=~/.*http[s]*:///" + $Z ...>;
          - pattern: |
              $Z = $REQ["host"];
              ...
              $X = <... "=~/.*http[s]*:///" + $Z ...>;
          - pattern: |
              $Z = $REQ("host");
              ...
              $X = <... "=~/.*http[s]*:///" + $Z ...>;
          - pattern: |
              $Z = $REQ.host;
              ...
              $X = { $Y: <... "=~/.*http[s]*:///" + $REQ.host ...>};
          - pattern: |
              $Z = $REQ["host"];
              ...
              $X = { $Y: <... "=~/.*http[s]*:///" + $Z ...>};
          - pattern: |
              $Z = $REQ("host");
              ...
              $X = { $Y: <... "=~/.*http[s]*:///" + $REQ("host") ...>};
    message: Using untrusted Host header for generating dynamic URLs can result in
      web cache and or password reset poisoning.
    languages:
      - javascript
    severity: ERROR
    metadata:
      owasp: A01:2017 - Injection
      cwe: "CWE-20: Improper Input Validation"
      category: security
      technology:
        - node.js
        - express
      license: Commons Clause License Condition v1.0[LGPL-2.1-only]

Examples

host_header_injection.js

// https://www.acunetix.com/blog/articles/automated-detection-of-host-header-attacks/
app.get('/', function (req, res) {

    //semgrep string lateral support is pending
    var foo = {
        text: `reset url: https://${req.host}/password_reset/${token}`
    };

    //do not match
    var x = 'https://' + foo
    // do not match
    var x = "https://" + req.foo + "/reset" + foo;
    // do not match
    var x = "https://" + z + "/reset";



    // ruleid:host_header_injection
    var url = 'http://' + req.host;
    // ruleid:host_header_injection
    var reset = 'https://' + req.host + '/password_reset';
    // ruleid:host_header_injection
    var pass = "https://" + req.host + "/reset";

    // ruleid:host_header_injection
    var z = req.host;
    var pass = "https://" + z + "/reset";

    // ruleid:host_header_injection
    var reset_url = "Reset password: <a href='http://" + req.host + "/reset_pass'>Reset</a>";
    // ruleid:host_header_injection
    var foo = {
        text: 'password: https://' + req.host + '/token/',
        token: 'f2131ASDSADASoo',
    };

    // ruleid:host_header_injection
    var foo = {
        text: 'reset password: https://' + req['host'] + '/token/',
        token: 'f2131ASDSADASoo',
    };

    // ruleid:host_header_injection
    let x = "https://" + req['host'] + "/reset" + foo;
    // ruleid:host_header_injection
    x = "https://" + req("host") + "/reset" + foo + 'barr' + foo2;

    // ruleid:host_header_injection
    var foo = {
        text: 'reset password: https://' + req.host + '/resettoken/' + foo,
        token: 'f2131ASDSADASoo',
    };

});