generic.html-templates.security.var-in-script-src.var-in-script-src

profile photo of semgrepsemgrep
Author
225
Download Count*

Detected a template variable used as the 'src' in a script tag. Although template variables are HTML escaped, HTML escaping does not always prevent malicious URLs from being injected and could results in a cross-site scripting (XSS) vulnerability. Prefer not to dynamically generate the 'src' attribute and use static URLs instead. If you must do this, carefully check URLs against an allowlist and be sure to URL-encode the result.

Run Locally

Run in CI

Defintion

rules:
  - id: var-in-script-src
    message: Detected a template variable used as the 'src' in a script tag.
      Although template variables are HTML escaped, HTML escaping does not
      always prevent malicious URLs from being injected and could results in a
      cross-site scripting (XSS) vulnerability. Prefer not to dynamically
      generate the 'src' attribute and use static URLs instead. If you must do
      this, carefully check URLs against an allowlist and be sure to URL-encode
      the result.
    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://adamj.eu/tech/2020/02/18/safely-including-data-for-javascript-in-a-django-template/?utm_campaign=Django%2BNewsletter&utm_medium=rss&utm_source=Django_Newsletter_12A
        - https://www.veracode.com/blog/secure-development/nodejs-template-engines-why-default-encoders-are-not-enough
        - https://github.com/ESAPI/owasp-esapi-js
      category: security
      technology:
        - html-templates
      confidence: LOW
      cwe2022-top25: true
      cwe2021-top25: true
      subcategory:
        - audit
      likelihood: LOW
      impact: MEDIUM
      license: Commons Clause License Condition v1.0[LGPL-2.1-only]
      vulnerability_class:
        - Cross-Site-Scripting (XSS)
    languages:
      - generic
    paths:
      include:
        - "*.mustache"
        - "*.hbs"
        - "*.html"
    severity: WARNING
    patterns:
      - pattern-inside: <script ...>
      - pattern-not-inside: src = '...'
      - pattern-not-inside: src = "..."
      - pattern-not-inside: nonce = '...'
      - pattern-not-inside: nonce = "..."
      - pattern: "{{ ... }}"

Examples

var-in-script-src.html

<!-- cf. https://github.com/caiomartini/mustache-demo/blob/97b9200ebd2d27953febff23e6718aa1aa9ee44d/demo-mustache.html -->
<!DOCTYPE HTML>
<html>

<head>
    <title>Demo Mustache.JS</title>
    <meta charset="utf-8">
    <link rel="stylesheet" href="node_modules\bootstrap\dist\css\bootstrap.min.css">
    <script type="text/javascript" src="node_modules\jquery\dist\jquery.min.js"></script>
    <script type="text/javascript" src="node_modules\bootstrap\dist\js\bootstrap.min.js"></script>
    <script type="text/javascript" src="node_modules\mustache\mustache.min.js"></script>
    <script type="text/javascript" src="demo-mustache.js"></script>
</head>

<!-- ok: var-in-script-src -->
<script src="app.js"></script>
<!-- ok: var-in-script-src -->
<script src="script.js"></script>

<div class="text-center">
    <!-- ok: var-in-script-src -->
    <h2>Apresentando o time da <b>{{ time.nome }}</b></h2>
    <!-- ok: var-in-script-src -->
    <h6>Predio {{ time.predio }}</h6>
</div>
<div class="container" style="margin-top: 30px;">
    <div class="row">
        <div class="col-sm-6">
            <div class="card">
                <div class="card-header text-center">
                    <!-- ok: var-in-script-src -->
                    <b>{{ nome }}</b>
                </div>
                <div class="card-body">
                    <!-- ok: var-in-script-src -->
                    {{ template-table }}
                </div>
            </div>
        </div>
    </div>
</div>

<!-- ruleid: var-in-script-src -->
<script src="./{{ reactDemoIndexBundleJs }}" crossOrigin="anonymous" integrity="{{ sri.reactDemoIndexBundleJs }}"></script>

<script nonce="{{ request.csp_nonce }}">
  console.log('inline script running');
</script>

</html>