python.django.security.injection.email.xss-html-email-body.xss-html-email-body

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

Found request data in an EmailMessage that is set to use HTML. 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-html-email-body
    message: Found request data in an EmailMessage that is set to use HTML. 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(...):
            ...
            $EMAIL.content_subtype = "html"
            ...
      - pattern-either:
          - pattern: django.core.mail.EmailMessage($SUBJ, request.$W.get(...), ...)
          - pattern: |
              $DATA = request.$W.get(...)
              ...
              django.core.mail.EmailMessage($SUBJ, $DATA, ...)
          - pattern: |
              $DATA = request.$W.get(...)
              ...
              $INTERM = $DATA
              ...
              django.core.mail.EmailMessage($SUBJ, $INTERM, ...)
          - pattern: |
              $DATA = request.$W.get(...)
              ...
              django.core.mail.EmailMessage($SUBJ, $B.$C(..., $DATA, ...), ...)
          - pattern: |
              $DATA = request.$W.get(...)
              ...
              $INTERM = $B.$C(..., $DATA, ...)
              ...
              django.core.mail.EmailMessage($SUBJ, $INTERM, ...)
          - pattern: |
              $DATA = request.$W.get(...)
              ...
              django.core.mail.EmailMessage($SUBJ, $STR % $DATA, ...)
          - pattern: |
              $DATA = request.$W.get(...)
              ...
              $INTERM = $STR % $DATA
              ...
              django.core.mail.EmailMessage($SUBJ, $INTERM, ...)
          - pattern: |
              $DATA = request.$W.get(...)
              ...
              django.core.mail.EmailMessage($SUBJ, f"...{$DATA}...", ...)
          - pattern: |
              $DATA = request.$W.get(...)
              ...
              $INTERM = f"...{$DATA}..."
              ...
              django.core.mail.EmailMessage($SUBJ, $INTERM, ...)
          - pattern: $A = django.core.mail.EmailMessage($SUBJ, request.$W.get(...), ...)
          - pattern: return django.core.mail.EmailMessage($SUBJ, request.$W.get(...), ...)
          - pattern: django.core.mail.EmailMessage($SUBJ, request.$W(...), ...)
          - pattern: |
              $DATA = request.$W(...)
              ...
              django.core.mail.EmailMessage($SUBJ, $DATA, ...)
          - pattern: |
              $DATA = request.$W(...)
              ...
              $INTERM = $DATA
              ...
              django.core.mail.EmailMessage($SUBJ, $INTERM, ...)
          - pattern: |
              $DATA = request.$W(...)
              ...
              django.core.mail.EmailMessage($SUBJ, $B.$C(..., $DATA, ...), ...)
          - pattern: |
              $DATA = request.$W(...)
              ...
              $INTERM = $B.$C(..., $DATA, ...)
              ...
              django.core.mail.EmailMessage($SUBJ, $INTERM, ...)
          - pattern: |
              $DATA = request.$W(...)
              ...
              django.core.mail.EmailMessage($SUBJ, $STR % $DATA, ...)
          - pattern: |
              $DATA = request.$W(...)
              ...
              $INTERM = $STR % $DATA
              ...
              django.core.mail.EmailMessage($SUBJ, $INTERM, ...)
          - pattern: |
              $DATA = request.$W(...)
              ...
              django.core.mail.EmailMessage($SUBJ, f"...{$DATA}...", ...)
          - pattern: |
              $DATA = request.$W(...)
              ...
              $INTERM = f"...{$DATA}..."
              ...
              django.core.mail.EmailMessage($SUBJ, $INTERM, ...)
          - pattern: $A = django.core.mail.EmailMessage($SUBJ, request.$W(...), ...)
          - pattern: return django.core.mail.EmailMessage($SUBJ, request.$W(...), ...)
          - pattern: django.core.mail.EmailMessage($SUBJ, request.$W[...], ...)
          - pattern: |
              $DATA = request.$W[...]
              ...
              django.core.mail.EmailMessage($SUBJ, $DATA, ...)
          - pattern: |
              $DATA = request.$W[...]
              ...
              $INTERM = $DATA
              ...
              django.core.mail.EmailMessage($SUBJ, $INTERM, ...)
          - pattern: |
              $DATA = request.$W[...]
              ...
              django.core.mail.EmailMessage($SUBJ, $B.$C(..., $DATA, ...), ...)
          - pattern: |
              $DATA = request.$W[...]
              ...
              $INTERM = $B.$C(..., $DATA, ...)
              ...
              django.core.mail.EmailMessage($SUBJ, $INTERM, ...)
          - pattern: |
              $DATA = request.$W[...]
              ...
              django.core.mail.EmailMessage($SUBJ, $STR % $DATA, ...)
          - pattern: |
              $DATA = request.$W[...]
              ...
              $INTERM = $STR % $DATA
              ...
              django.core.mail.EmailMessage($SUBJ, $INTERM, ...)
          - pattern: |
              $DATA = request.$W[...]
              ...
              django.core.mail.EmailMessage($SUBJ, f"...{$DATA}...", ...)
          - pattern: |
              $DATA = request.$W[...]
              ...
              $INTERM = f"...{$DATA}..."
              ...
              django.core.mail.EmailMessage($SUBJ, $INTERM, ...)
          - pattern: $A = django.core.mail.EmailMessage($SUBJ, request.$W[...], ...)
          - pattern: return django.core.mail.EmailMessage($SUBJ, request.$W[...], ...)
          - pattern: django.core.mail.EmailMessage($SUBJ, request.$W, ...)
          - pattern: |
              $DATA = request.$W
              ...
              django.core.mail.EmailMessage($SUBJ, $DATA, ...)
          - pattern: |
              $DATA = request.$W
              ...
              $INTERM = $DATA
              ...
              django.core.mail.EmailMessage($SUBJ, $INTERM, ...)
          - pattern: |
              $DATA = request.$W
              ...
              django.core.mail.EmailMessage($SUBJ, $B.$C(..., $DATA, ...), ...)
          - pattern: |
              $DATA = request.$W
              ...
              $INTERM = $B.$C(..., $DATA, ...)
              ...
              django.core.mail.EmailMessage($SUBJ, $INTERM, ...)
          - pattern: |
              $DATA = request.$W
              ...
              django.core.mail.EmailMessage($SUBJ, $STR % $DATA, ...)
          - pattern: |
              $DATA = request.$W
              ...
              $INTERM = $STR % $DATA
              ...
              django.core.mail.EmailMessage($SUBJ, $INTERM, ...)
          - pattern: |
              $DATA = request.$W
              ...
              django.core.mail.EmailMessage($SUBJ, f"...{$DATA}...", ...)
          - pattern: |
              $DATA = request.$W
              ...
              $INTERM = f"...{$DATA}..."
              ...
              django.core.mail.EmailMessage($SUBJ, $INTERM, ...)
          - pattern: $A = django.core.mail.EmailMessage($SUBJ, request.$W, ...)
          - pattern: return django.core.mail.EmailMessage($SUBJ, request.$W, ...)

Examples

xss-html-email-body.py

import logging as logger
import traceback
from django.contrib.auth.models import User
from django.conf import settings
from django.core.mail import EmailMessage
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")
            # ruleid: xss-html-email-body
            body_html = request.POST.get("body")

            sender = settings.EMAIL_SENDER

            email = EmailMessage(
                subject,
                body_html,
                sender,
                [settings.EMAIL],
                bcc=users,
            )
            email.content_subtype = "html"

            try:
                email.send()
                return render(
                    request,
                    "notification_email_conformation.html",
                    {"message": "All the emails are sent successfully!"},
                )
            except SMTPException:
                logger.exception(traceback.format_exc())
                return render(
                    request, "notification_email_data.html", {"errors": 1}
                )
        else:
            return render(request, "error404.html")
    else:
        return render(request, "error404.html")

def send_an_email(request):
    subject = request.POST.get("subject")
    # ok: xss-html-email-body
    body_html = request.POST.get("body")

    sender = "blah@blah.com"
    email = EmailMessage(
        subject,
        body_html,
        sender,
        [settings.EMAIL],
    )

    try:
        email.send()
        return render(
            request,
            "notification_email_conformation.html",
            {"message": "All the emails are sent successfully!"},
        )
    except SMTPException:
        logger.exception(traceback.format_exc())
        return render(
            request, "notification_email_data.html", {"errors": 1}
        )