python.flask.security.xss.audit.template-unquoted-attribute-var.template-unquoted-attribute-var

Community Favorite
profile photo of returntocorpreturntocorp
Author
12,105
Download Count*

Detected a unquoted template variable as an attribute. If unquoted, a malicious actor could inject custom JavaScript handlers. To fix this, add quotes around the template expression, like this: "{{ $...VAR }}".

Run Locally

Run in CI

Defintion

rules:
  - id: template-unquoted-attribute-var
    message: 'Detected a unquoted template variable as an attribute. If unquoted, a
      malicious actor could inject custom JavaScript handlers. To fix this, add
      quotes around the template expression, like this: "{{ $...VAR }}".'
    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://flask.palletsprojects.com/en/1.1.x/security/#cross-site-scripting-xss
      category: security
      technology:
        - flask
      license: Commons Clause License Condition v1.0[LGPL-2.1-only]
      cwe2022-top25: true
      cwe2021-top25: true
      subcategory:
        - audit
      likelihood: LOW
      impact: MEDIUM
      confidence: LOW
      vulnerability_class:
        - Cross-Site-Scripting (XSS)
    languages:
      - generic
    paths:
      include:
        - "*.html"
        - "*.py"
    severity: WARNING
    patterns:
      - pattern: ={{$...VAR}}
      - pattern-inside: |
          <$TAG ... >
      - metavariable-pattern:
          metavariable: $...VAR
          pattern-either:
            - pattern: |
                request.$VALUE.get(...)
            - pattern: |
                request.$VALUE['...']
            - patterns:
                - pattern: $REQ
                - pattern-either:
                    - pattern-inside: |
                        $REQ = request.$VALUE.get(...)
                        ... 
                    - pattern-inside: |
                        $REQ = request.$VALUE['...']
                        ... 
    fix: |
      ="{{$...VAR}}"

Examples

template-unquoted-attribute-var.html

<table><tbody>
  <tr>
    <!-- ruleid: template-unquoted-attribute-var-->
    <td class="input"><input type="text" value={{ a + request.args.get('a') }}/></td>
  </tr>
  <tr>
    <td><input type="number" id="issue" name="issue" value={{ value }} min="1"/></td>
  </tr>
  <tr>
    <td><label for="head">Head:</label></td>
    <!-- ok: template-unquoted-attribute-var-->
    <td><input type="text" id="head" name="head" value="{{ request.args.get('head', '') }}" placeholder="ex. [user:]bugfix"/></td>
  </tr>
</tbody></table>    

template-unquoted-attribute-var.py

from flask import Flask, request, session, redirect, url_for, flash
from flask import render_template_string
from flask_github import GitHub, GitHubError

app = Flask(__name__)
app.config.from_object(__name__)

github = GitHub(app)

HTMLBLOB = """
<!DOCTYPE HTML>
<html>
<table><tbody>
<tr>
    <td class="label"><label for="repo">Repository:</label></td>
    <!-- ok: template-unquoted-attribute-var -->
    <td class="input"><input type="text" id="repo" name="repo" value="{{ request.args.get('repo', '') }}" /></td>
</tr>
<tr>
    <td><label for="issue">Issue:</label></td>
    <!-- ruleid: template-unquoted-attribute-var -->
    <td><input type="number" id="issue" name="issue" value={{ request.args.get('issue', '1')}} min="1"/></td>
</tr>
</tbody></table>
</html>"""

@app.route('/')
def index():
    return render_template_string(HTMLBLOB)

if __name__ == "__main__":
    app.run(host='0.0.0.0', port=5000)