python.django.security.injection.email.xss-send-mail-html-message.xss-send-mail-html-message

Verifed by r2c
Community Favorite
profile photo of semgrepsemgrep
Author
99,207
Download Count*

Found request data in 'send_mail(...)' that uses 'html_message'. This is dangerous because HTML emails are susceptible to XSS. An attacker could inject data into this HTML email, causing XSS.

Run Locally

Run in CI

Defintion

rules:
  - id: xss-send-mail-html-message
    message: Found request data in 'send_mail(...)' that uses 'html_message'. This
      is dangerous because HTML emails are susceptible to XSS. An attacker could
      inject data into this HTML email, causing XSS.
    metadata:
      cwe:
        - "CWE-74: Improper Neutralization of Special Elements in Output Used by
          a Downstream Component ('Injection')"
      owasp:
        - A03:2021 - Injection
      references:
        - https://www.damonkohler.com/2008/12/email-injection.html
      category: security
      technology:
        - django
      subcategory:
        - vuln
      likelihood: MEDIUM
      impact: MEDIUM
      confidence: MEDIUM
      license: Commons Clause License Condition v1.0[LGPL-2.1-only]
      vulnerability_class:
        - Other
    languages:
      - python
    severity: WARNING
    patterns:
      - pattern-inside: |
          def $FUNC(...):
            ...
      - pattern-either:
          - pattern: django.core.mail.send_mail(..., html_message=request.$W.get(...), ...)
          - pattern: |
              $DATA = request.$W.get(...)
              ...
              django.core.mail.send_mail(..., html_message=$DATA, ...)
          - pattern: |
              $DATA = request.$W.get(...)
              ...
              $INTERM = $DATA
              ...
              django.core.mail.send_mail(..., html_message=$INTERM, ...)
          - pattern: >
              $DATA = request.$W.get(...)

              ...

              django.core.mail.send_mail(..., html_message=$STR.format(..., $DATA, ...), ...)
          - pattern: |
              $DATA = request.$W.get(...)
              ...
              $INTERM = $STR.format(..., $DATA, ...)
              ...
              django.core.mail.send_mail(..., html_message=$INTERM, ...)
          - pattern: |
              $DATA = request.$W.get(...)
              ...
              django.core.mail.send_mail(..., html_message=$STR % $DATA, ...)
          - pattern: |
              $DATA = request.$W.get(...)
              ...
              $INTERM = $STR % $DATA
              ...
              django.core.mail.send_mail(..., html_message=$INTERM, ...)
          - pattern: >
              $DATA = request.$W.get(...)

              ...

              django.core.mail.send_mail(..., html_message=f"...{$DATA}...", ...)
          - pattern: |
              $DATA = request.$W.get(...)
              ...
              $INTERM = f"...{$DATA}..."
              ...
              django.core.mail.send_mail(..., html_message=$INTERM, ...)
          - pattern: |
              $DATA = request.$W.get(...)
              ...
              django.core.mail.send_mail(..., html_message=$STR + $DATA, ...)
          - pattern: |
              $DATA = request.$W.get(...)
              ...
              $INTERM = $STR + $DATA
              ...
              django.core.mail.send_mail(..., html_message=$INTERM, ...)
          - pattern: $A = django.core.mail.send_mail(..., html_message=request.$W.get(...),
              ...)
          - pattern: return django.core.mail.send_mail(...,
              html_message=request.$W.get(...), ...)
          - pattern: django.core.mail.send_mail(..., html_message=request.$W(...), ...)
          - pattern: |
              $DATA = request.$W(...)
              ...
              django.core.mail.send_mail(..., html_message=$DATA, ...)
          - pattern: |
              $DATA = request.$W(...)
              ...
              $INTERM = $DATA
              ...
              django.core.mail.send_mail(..., html_message=$INTERM, ...)
          - pattern: >
              $DATA = request.$W(...)

              ...

              django.core.mail.send_mail(..., html_message=$STR.format(..., $DATA, ...), ...)
          - pattern: |
              $DATA = request.$W(...)
              ...
              $INTERM = $STR.format(..., $DATA, ...)
              ...
              django.core.mail.send_mail(..., html_message=$INTERM, ...)
          - pattern: |
              $DATA = request.$W(...)
              ...
              django.core.mail.send_mail(..., html_message=$STR % $DATA, ...)
          - pattern: |
              $DATA = request.$W(...)
              ...
              $INTERM = $STR % $DATA
              ...
              django.core.mail.send_mail(..., html_message=$INTERM, ...)
          - pattern: >
              $DATA = request.$W(...)

              ...

              django.core.mail.send_mail(..., html_message=f"...{$DATA}...", ...)
          - pattern: |
              $DATA = request.$W(...)
              ...
              $INTERM = f"...{$DATA}..."
              ...
              django.core.mail.send_mail(..., html_message=$INTERM, ...)
          - pattern: |
              $DATA = request.$W(...)
              ...
              django.core.mail.send_mail(..., html_message=$STR + $DATA, ...)
          - pattern: |
              $DATA = request.$W(...)
              ...
              $INTERM = $STR + $DATA
              ...
              django.core.mail.send_mail(..., html_message=$INTERM, ...)
          - pattern: $A = django.core.mail.send_mail(..., html_message=request.$W(...), ...)
          - pattern: return django.core.mail.send_mail(..., html_message=request.$W(...),
              ...)
          - pattern: django.core.mail.send_mail(..., html_message=request.$W[...], ...)
          - pattern: |
              $DATA = request.$W[...]
              ...
              django.core.mail.send_mail(..., html_message=$DATA, ...)
          - pattern: |
              $DATA = request.$W[...]
              ...
              $INTERM = $DATA
              ...
              django.core.mail.send_mail(..., html_message=$INTERM, ...)
          - pattern: >
              $DATA = request.$W[...]

              ...

              django.core.mail.send_mail(..., html_message=$STR.format(..., $DATA, ...), ...)
          - pattern: |
              $DATA = request.$W[...]
              ...
              $INTERM = $STR.format(..., $DATA, ...)
              ...
              django.core.mail.send_mail(..., html_message=$INTERM, ...)
          - pattern: |
              $DATA = request.$W[...]
              ...
              django.core.mail.send_mail(..., html_message=$STR % $DATA, ...)
          - pattern: |
              $DATA = request.$W[...]
              ...
              $INTERM = $STR % $DATA
              ...
              django.core.mail.send_mail(..., html_message=$INTERM, ...)
          - pattern: >
              $DATA = request.$W[...]

              ...

              django.core.mail.send_mail(..., html_message=f"...{$DATA}...", ...)
          - pattern: |
              $DATA = request.$W[...]
              ...
              $INTERM = f"...{$DATA}..."
              ...
              django.core.mail.send_mail(..., html_message=$INTERM, ...)
          - pattern: |
              $DATA = request.$W[...]
              ...
              django.core.mail.send_mail(..., html_message=$STR + $DATA, ...)
          - pattern: |
              $DATA = request.$W[...]
              ...
              $INTERM = $STR + $DATA
              ...
              django.core.mail.send_mail(..., html_message=$INTERM, ...)
          - pattern: $A = django.core.mail.send_mail(..., html_message=request.$W[...], ...)
          - pattern: return django.core.mail.send_mail(..., html_message=request.$W[...],
              ...)
          - pattern: django.core.mail.send_mail(..., html_message=request.$W, ...)
          - pattern: |
              $DATA = request.$W
              ...
              django.core.mail.send_mail(..., html_message=$DATA, ...)
          - pattern: |
              $DATA = request.$W
              ...
              $INTERM = $DATA
              ...
              django.core.mail.send_mail(..., html_message=$INTERM, ...)
          - pattern: >
              $DATA = request.$W

              ...

              django.core.mail.send_mail(..., html_message=$STR.format(..., $DATA, ...), ...)
          - pattern: |
              $DATA = request.$W
              ...
              $INTERM = $STR.format(..., $DATA, ...)
              ...
              django.core.mail.send_mail(..., html_message=$INTERM, ...)
          - pattern: |
              $DATA = request.$W
              ...
              django.core.mail.send_mail(..., html_message=$STR % $DATA, ...)
          - pattern: |
              $DATA = request.$W
              ...
              $INTERM = $STR % $DATA
              ...
              django.core.mail.send_mail(..., html_message=$INTERM, ...)
          - pattern: >
              $DATA = request.$W

              ...

              django.core.mail.send_mail(..., html_message=f"...{$DATA}...", ...)
          - pattern: |
              $DATA = request.$W
              ...
              $INTERM = f"...{$DATA}..."
              ...
              django.core.mail.send_mail(..., html_message=$INTERM, ...)
          - pattern: |
              $DATA = request.$W
              ...
              django.core.mail.send_mail(..., html_message=$STR + $DATA, ...)
          - pattern: |
              $DATA = request.$W
              ...
              $INTERM = $STR + $DATA
              ...
              django.core.mail.send_mail(..., html_message=$INTERM, ...)
          - pattern: $A = django.core.mail.send_mail(..., html_message=request.$W, ...)
          - pattern: return django.core.mail.send_mail(..., html_message=request.$W, ...)

Examples

xss-send-mail-html-message.py

import logging as logger
import traceback
from django.contrib.auth.models import User
from django.conf import settings
from django.core.mail import send_mail
from django.shortcuts import render

from smtplib import SMTPException

def notify_users_about_challenge(request):
    """
    Email New Challenge Details to Users
    """
    if request.user.is_authenticated() and request.user.is_superuser:
        if request.method == "GET":
            template_name = "notification_email_data.html"
            return render(request, template_name)

        elif request.method == "POST":
            users = User.objects.exclude(email__exact="").values_list(
                "email", flat=True
            )
            subject = request.POST.get("subject")
            body = request.POST.get("body")
            # ruleid: xss-send-mail-html-message
            body_html = request.POST.get("body_html")

            sender = settings.EMAIL_SENDER

            send_mail(
                subject,
                body,
                sender,
                [settings.EMAIL],
                bcc=users,
                html_message=body_html
            )
        else:
            return render(request, "error404.html")
    else:
        return render(request, "error404.html")

def send_an_email(request):
    subject = request.POST.get("subject")
    # ok: xss-send-mail-html-message
    body= request.POST.get("body")

    sender = "blah@blah.com"
    send_mail(
        subject,
        body,
        sender,
        [settings.EMAIL],
    )