javascript.jquery.security.audit.jquery-insecure-method.jquery-insecure-method

profile photo of semgrepsemgrep
Author
6,418
Download Count*

User controlled data in a jQuery's .$METHOD(...) is an anti-pattern that can lead to XSS vulnerabilities

Run Locally

Run in CI

Defintion

rules:
  - id: jquery-insecure-method
    message: User controlled data in a jQuery's `.$METHOD(...)` is an anti-pattern
      that can lead to XSS vulnerabilities
    metadata:
      cwe:
        - "CWE-79: Improper Neutralization of Input During Web Page Generation
          ('Cross-site Scripting')"
      owasp:
        - A07:2017 - Cross-Site Scripting (XSS)
        - A03:2021 - Injection
      references:
        - https://owasp.org/www-community/attacks/xss/
        - https://bugs.jquery.com/ticket/9521
      category: security
      technology:
        - jquery
      cwe2022-top25: true
      cwe2021-top25: true
      subcategory:
        - audit
      likelihood: LOW
      impact: MEDIUM
      confidence: LOW
      license: Commons Clause License Condition v1.0[LGPL-2.1-only]
      vulnerability_class:
        - Cross-Site-Scripting (XSS)
    languages:
      - javascript
      - typescript
    severity: WARNING
    options:
      symbolic_propagation: true
    pattern-either:
      - patterns:
          - pattern-either:
              - pattern: $.$METHOD($VAR,...)
              - pattern: $(...).$METHOD($VAR,...)
              - pattern: jQuery.$METHOD($VAR,...)
              - pattern: jQuery(...).$METHOD($VAR,...)
          - pattern-not: $.$METHOD("...",...)
          - pattern-not: $(...).$METHOD("...",...)
          - pattern-not: jQuery.$METHOD("...",...)
          - pattern-not: jQuery(...).$METHOD("...",...)
          - metavariable-regex:
              metavariable: $METHOD
              regex: ^(html|append|prepend|wrap|wrapInner|wrapAll|before|after|globalEval|getScript)$
      - patterns:
          - pattern-either:
              - pattern: $(...).$METHOD($VAR,...)
              - pattern: jQuery(...).$METHOD($VAR,...)
          - pattern-not: $("...",...).$METHOD(...)
          - pattern-not: jQuery("...",...).$METHOD(...)
          - metavariable-regex:
              metavariable: $METHOD
              regex: ^(appendTo|insertAfter|insertBefore|prependTo)$

Examples

jquery-insecure-method.js

(function ($) {

  function bad1() {
    var content = '<div>' + window.location.hash + '</div>';
    // ruleid: jquery-insecure-method
    $( "div" ).html( content );
  }

  function bad2() {
    // ruleid: jquery-insecure-method
    $( userInput ).appendTo( "#foo" );
  }

  function bad4() {
    // ruleid: jquery-insecure-method
    $('<div>' + window.location.hash + '</div>').insertBefore( ".inner" );
    // ruleid: jquery-insecure-method
    $('.inner').prepend(window.location.hash);
    function test() {
    // ruleid: jquery-insecure-method
      jQuery.globalEval('<div>' + window.location.hash + '</div>', {
        nonce: "nonce-2726c7f26c"
      } );
    }
  }

  function bad5(userInput) {
    // ruleid: jquery-insecure-method
    $( ".inner" ).wrap( "<div class='new'>" + userInput + "</div>" );
    // ruleid: jquery-insecure-method
    $( "p" ).wrapAll(userInput);
  }


  function bad6() {
    $.get(
      `/foo/${x}`,
      (response) => {
        let select = $('foo')
        for (let d of response.data) {
            let bar = $(new Data(d))
            // ruleid: jquery-insecure-method
            select.append(bar)
        }
      }
    );
  }

  function ok1() {
    const item = '<div></div>';
    // ok: jquery-insecure-method
    $( ".inner" ).wrap(item);
  }

  function ok2(userInput) {
    // ok: jquery-insecure-method
    $( "div" ).html( '<div></div>' );
  }

  function ok3(userInput) {
    jQuery(document).ready(function($){
      // ok: jquery-insecure-method
      $('<input type="checkbox"/>').prependTo('.checklist-box li');
    });
  }

  function ok4(userInput) {
      // ok: jquery-insecure-method
      var url = this.prependRestapi(userInput);
      fooBar(url);
  }

})(jQUery);