javascript.angular.security.detect-angular-element-taint.detect-angular-element-taint

profile photo of semgrepsemgrep
Author
unknown
Download Count*

Use of angular.element can lead to XSS if user-input is treated as part of the HTML element within $SINK. It is recommended to contextually output encode user-input, before inserting into $SINK. If the HTML needs to be preserved it is recommended to sanitize the input using $sce.getTrustedHTML or $sanitize.

Run Locally

Run in CI

Defintion

rules:
  - id: detect-angular-element-taint
    message: Use of angular.element can lead to XSS if user-input is treated as part
      of the HTML element within `$SINK`. It is recommended to contextually
      output encode user-input, before inserting into `$SINK`. If the HTML needs
      to be preserved it is recommended to sanitize the input using
      $sce.getTrustedHTML or $sanitize.
    metadata:
      confidence: MEDIUM
      cwe:
        - "CWE-79: Improper Neutralization of Input During Web Page Generation
          ('Cross-site Scripting')"
      references:
        - https://docs.angularjs.org/api/ng/function/angular.element
        - https://owasp.org/www-chapter-london/assets/slides/OWASPLondon20170727_AngularJS.pdf
      category: security
      technology:
        - angularjs
      owasp:
        - A07:2017 - Cross-Site Scripting (XSS)
        - A03:2021 - Injection
      cwe2022-top25: true
      cwe2021-top25: true
      subcategory:
        - vuln
      likelihood: HIGH
      impact: MEDIUM
      license: Commons Clause License Condition v1.0[LGPL-2.1-only]
      vulnerability_class:
        - Cross-Site-Scripting (XSS)
    languages:
      - javascript
      - typescript
    severity: WARNING
    mode: taint
    pattern-sources:
      - patterns:
          - pattern-either:
              - pattern: window.location.search
              - pattern: window.document.location.search
              - pattern: document.location.search
              - pattern: location.search
              - pattern: $location.search(...)
      - patterns:
          - pattern-either:
              - pattern: $DECODE(<... location.hash ...>)
              - pattern: $DECODE(<... window.location.hash ...>)
              - pattern: $DECODE(<... document.location.hash ...>)
              - pattern: $DECODE(<... location.href ...>)
              - pattern: $DECODE(<... window.location.href ...>)
              - pattern: $DECODE(<... document.location.href ...>)
              - pattern: $DECODE(<... document.URL ...>)
              - pattern: $DECODE(<... window.document.URL ...>)
              - pattern: $DECODE(<... document.location.href ...>)
              - pattern: $DECODE(<... document.location.href ...>)
              - pattern: $DECODE(<... $location.absUrl() ...>)
              - pattern: $DECODE(<... $location.url() ...>)
              - pattern: $DECODE(<... $location.hash() ...>)
          - metavariable-regex:
              metavariable: $DECODE
              regex: ^(unescape|decodeURI|decodeURIComponent)$
      - patterns:
          - pattern-inside: $http.$METHOD(...).$CONTINUE(function $FUNC($RES) {...})
          - metavariable-regex:
              metavariable: $METHOD
              regex: ^(get|delete|head|jsonp|post|put|patch)
          - pattern: $RES.data
    pattern-sinks:
      - patterns:
          - pattern-either:
              - pattern-inside: |
                  angular.element(...). ... .$SINK($QUERY)
              - pattern-inside: |
                  $ANGULAR = angular.element(...)
                  ...
                  $ANGULAR. ... .$SINK($QUERY)
          - metavariable-regex:
              metavariable: $SINK
              regex: ^(after|append|html|prepend|replaceWith|wrap)$
          - focus-metavariable: $QUERY
    pattern-sanitizers:
      - patterns:
          - pattern-either:
              - pattern: $sce.getTrustedHtml(...)
              - pattern: $sanitize(...)
              - pattern: DOMPurify.sanitize(...)

Examples

detect-angular-element-taint.js

var app = angular.module('MyApp', []);
app.controller('myCtrl', function($scope,$sanitize) {
    let a = unescape(window.location.href)
    // ruleid: detect-angular-element-taint
    angular.element('div').html(a)
    let b = $sanitize(unescape(window.location.href))
    // ok: detect-angular-element-taint
    angular.element('div').html(b)
    let b = window.location.href
    // ruleid: detect-angular-element-taint
    angular.element('div').html((new URLSearchParams(window.location.search)).get('returnUrl'))

});