Merge pull request #7127 from jty-team/jty/python/emailInjection

Python: CWE-079 - Add Email injection query
This commit is contained in:
yoff 2022-06-14 10:54:16 +02:00 коммит произвёл GitHub
Родитель f7cc46b84b 171239b78f
Коммит 699761889d
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
16 изменённых файлов: 1023 добавлений и 1 удалений

Просмотреть файл

@ -0,0 +1,23 @@
/**
* @name Reflected server-side cross-site scripting
* @description Writing user input directly to a web page
* allows for a cross-site scripting vulnerability.
* @kind path-problem
* @problem.severity error
* @security-severity 2.9
* @sub-severity high
* @id py/reflective-xss
* @tags security
* external/cwe/cwe-079
* external/cwe/cwe-116
*/
// determine precision above
import python
import experimental.semmle.python.security.dataflow.ReflectedXSS
import DataFlow::PathGraph
from ReflectedXssConfiguration config, DataFlow::PathNode source, DataFlow::PathNode sink
where config.hasFlowPath(source, sink)
select sink.getNode(), source, sink, "Cross-site scripting vulnerability due to $@.",
source.getNode(), "a user-provided value"

Просмотреть файл

@ -602,3 +602,77 @@ class JwtDecoding extends DataFlow::Node instanceof JwtDecoding::Range {
/** DEPRECATED: Alias for JwtDecoding */
deprecated class JWTDecoding = JwtDecoding;
/** Provides classes for modeling Email APIs. */
module EmailSender {
/**
* A data-flow node that sends an email.
*
* Extend this class to model new APIs. If you want to refine existing API models,
* extend `EmailSender` instead.
*/
abstract class Range extends DataFlow::Node {
/**
* Gets a data flow node holding the plaintext version of the email body.
*/
abstract DataFlow::Node getPlainTextBody();
/**
* Gets a data flow node holding the html version of the email body.
*/
abstract DataFlow::Node getHtmlBody();
/**
* Gets a data flow node holding the recipients of the email.
*/
abstract DataFlow::Node getTo();
/**
* Gets a data flow node holding the senders of the email.
*/
abstract DataFlow::Node getFrom();
/**
* Gets a data flow node holding the subject of the email.
*/
abstract DataFlow::Node getSubject();
}
}
/**
* A data-flow node that sends an email.
*
* Extend this class to refine existing API models. If you want to model new APIs,
* extend `EmailSender::Range` instead.
*/
class EmailSender extends DataFlow::Node instanceof EmailSender::Range {
/**
* Gets a data flow node holding the plaintext version of the email body.
*/
DataFlow::Node getPlainTextBody() { result = super.getPlainTextBody() }
/**
* Gets a data flow node holding the html version of the email body.
*/
DataFlow::Node getHtmlBody() { result = super.getHtmlBody() }
/**
* Gets a data flow node holding the recipients of the email.
*/
DataFlow::Node getTo() { result = super.getTo() }
/**
* Gets a data flow node holding the senders of the email.
*/
DataFlow::Node getFrom() { result = super.getFrom() }
/**
* Gets a data flow node holding the subject of the email.
*/
DataFlow::Node getSubject() { result = super.getSubject() }
/**
* Gets a data flow node that refers to the HTML body or plaintext body of the email.
*/
DataFlow::Node getABody() { result in [super.getPlainTextBody(), super.getHtmlBody()] }
}

Просмотреть файл

@ -15,3 +15,6 @@ private import experimental.semmle.python.libraries.Python_JWT
private import experimental.semmle.python.libraries.Authlib
private import experimental.semmle.python.libraries.PythonJose
private import experimental.semmle.python.frameworks.CopyFile
private import experimental.semmle.python.frameworks.Sendgrid
private import experimental.semmle.python.libraries.FlaskMail
private import experimental.semmle.python.libraries.SmtpLib

Просмотреть файл

@ -8,8 +8,8 @@ private import semmle.python.frameworks.Django
private import semmle.python.dataflow.new.DataFlow
private import experimental.semmle.python.Concepts
private import semmle.python.ApiGraphs
import semmle.python.dataflow.new.RemoteFlowSources
private import semmle.python.Concepts
import semmle.python.dataflow.new.RemoteFlowSources
private module ExperimentalPrivateDjango {
private module DjangoMod {
@ -189,5 +189,90 @@ private module ExperimentalPrivateDjango {
}
}
}
module Email {
/** https://docs.djangoproject.com/en/3.2/topics/email/ */
private API::Node djangoMail() {
result = API::moduleImport("django").getMember("core").getMember("mail")
}
/**
* Gets a call to `django.core.mail.send_mail()`.
*
* Given the following example:
*
* ```py
* send_mail("Subject", "plain-text body", "from@example.com", ["to@example.com"], html_message=django.http.request.GET.get("html"))
* ```
*
* * `this` would be `send_mail("Subject", "plain-text body", "from@example.com", ["to@example.com"], html_message=django.http.request.GET.get("html"))`.
* * `getPlainTextBody()`'s result would be `"plain-text body"`.
* * `getHtmlBody()`'s result would be `django.http.request.GET.get("html")`.
* * `getTo()`'s result would be `["to@example.com"]`.
* * `getFrom()`'s result would be `"from@example.com"`.
* * `getSubject()`'s result would be `"Subject"`.
*/
private class DjangoSendMail extends DataFlow::CallCfgNode, EmailSender::Range {
DjangoSendMail() { this = djangoMail().getMember("send_mail").getACall() }
override DataFlow::Node getPlainTextBody() {
result in [this.getArg(1), this.getArgByName("message")]
}
override DataFlow::Node getHtmlBody() {
result in [this.getArg(8), this.getArgByName("html_message")]
}
override DataFlow::Node getTo() {
result in [this.getArg(3), this.getArgByName("recipient_list")]
}
override DataFlow::Node getFrom() {
result in [this.getArg(2), this.getArgByName("from_email")]
}
override DataFlow::Node getSubject() {
result in [this.getArg(0), this.getArgByName("subject")]
}
}
/**
* Gets a call to `django.core.mail.mail_admins()` or `django.core.mail.mail_managers()`.
*
* Given the following example:
*
* ```py
* mail_admins("Subject", "plain-text body", html_message=django.http.request.GET.get("html"))
* ```
*
* * `this` would be `mail_admins("Subject", "plain-text body", html_message=django.http.request.GET.get("html"))`.
* * `getPlainTextBody()`'s result would be `"plain-text body"`.
* * `getHtmlBody()`'s result would be `django.http.request.GET.get("html")`.
* * `getTo()`'s result would be `none`.
* * `getFrom()`'s result would be `none`.
* * `getSubject()`'s result would be `"Subject"`.
*/
private class DjangoMailInternal extends DataFlow::CallCfgNode, EmailSender::Range {
DjangoMailInternal() {
this = djangoMail().getMember(["mail_admins", "mail_managers"]).getACall()
}
override DataFlow::Node getPlainTextBody() {
result in [this.getArg(1), this.getArgByName("message")]
}
override DataFlow::Node getHtmlBody() {
result in [this.getArg(4), this.getArgByName("html_message")]
}
override DataFlow::Node getTo() { none() }
override DataFlow::Node getFrom() { none() }
override DataFlow::Node getSubject() {
result in [this.getArg(0), this.getArgByName("subject")]
}
}
}
}
}

Просмотреть файл

@ -0,0 +1,187 @@
/**
* Provides classes modeling security-relevant aspects of the `sendgrid` PyPI package.
* See https://github.com/sendgrid/sendgrid-python.
*/
private import python
private import semmle.python.dataflow.new.DataFlow
private import experimental.semmle.python.Concepts
private import semmle.python.ApiGraphs
private module Sendgrid {
/** Gets a reference to the `sendgrid` module. */
private API::Node sendgrid() { result = API::moduleImport("sendgrid") }
/** Gets a reference to `sendgrid.helpers.mail` */
private API::Node sendgridMailHelper() {
result = sendgrid().getMember("helpers").getMember("mail")
}
/** Gets a reference to `sendgrid.helpers.mail.Mail` */
private API::Node sendgridMailInstance() { result = sendgridMailHelper().getMember("Mail") }
/** Gets a reference to a `SendGridAPIClient` instance. */
private API::Node sendgridApiClient() {
result = sendgrid().getMember("SendGridAPIClient").getReturn()
}
/** Gets a reference to a `SendGridAPIClient` instance call with `send` or `post`. */
private DataFlow::CallCfgNode sendgridApiSendCall() {
result = sendgridApiClient().getMember("send").getACall()
or
result =
sendgridApiClient()
.getMember("client")
.getMember("mail")
.getMember("send")
.getMember("post")
.getACall()
}
/**
* Gets a reference to `sg.send()` and `sg.client.mail.send.post()`.
*
* Given the following example:
*
* ```py
* from_email = Email("from@example.com")
* to_email = To("to@example.com")
* subject = "Sending with SendGrid is Fun"
* content = Content("text/html", request.args["html_content"])
*
* mail = Mail(from_email, to_email, subject, content)
*
* sg = SendGridAPIClient(api_key='SENDGRID_API_KEY')
* response = sg.client.mail.send.post(request_body=mail.get())
* ```
*
* * `this` would be `sg.client.mail.send.post(request_body=mail.get())`.
* * `getPlainTextBody()`'s result would be `none()`.
* * `getHtmlBody()`'s result would be `request.args["html_content"]`.
* * `getTo()`'s result would be `"to@example.com"`.
* * `getFrom()`'s result would be `"from@example.com"`.
* * `getSubject()`'s result would be `"Sending with SendGrid is Fun"`.
*/
private class SendGridMail extends DataFlow::CallCfgNode, EmailSender::Range {
SendGridMail() { this = sendgridApiSendCall() }
private DataFlow::CallCfgNode getMailCall() {
exists(DataFlow::Node n |
n in [this.getArg(0), this.getArgByName("request_body")] and
result = [n, n.(DataFlow::MethodCallNode).getObject()].getALocalSource()
)
}
private DataFlow::Node sendgridContent(DataFlow::CallCfgNode contentCall, string mime) {
mime in ["text/plain", "text/html", "text/x-amp-html"] and
exists(StrConst mimeNode |
mimeNode.getText() = mime and
DataFlow::exprNode(mimeNode).(DataFlow::LocalSourceNode).flowsTo(contentCall.getArg(0)) and
result = contentCall.getArg(1)
)
}
private DataFlow::Node sendgridWrite(string attributeName) {
attributeName in ["plain_text_content", "html_content", "from_email", "subject"] and
exists(DataFlow::AttrWrite attrWrite |
attrWrite.getObject().getALocalSource() = this.getMailCall() and
attrWrite.getAttributeName() = attributeName and
result = attrWrite.getValue()
)
}
override DataFlow::Node getPlainTextBody() {
result in [
this.getMailCall().getArg(3), this.getMailCall().getArgByName("plain_text_content")
]
or
result in [
this.sendgridContent([
this.getMailCall().getArg(3), this.getMailCall().getArgByName("plain_text_content")
].getALocalSource(), "text/plain"),
this.sendgridContent(sendgridMailInstance().getMember("add_content").getACall(),
"text/plain")
]
or
result = this.sendgridWrite("plain_text_content")
}
override DataFlow::Node getHtmlBody() {
result in [this.getMailCall().getArg(4), this.getMailCall().getArgByName("html_content")]
or
result = this.getMailCall().getAMethodCall("set_html").getArg(0)
or
result =
this.sendgridContent([
this.getMailCall().getArg(4), this.getMailCall().getArgByName("html_content")
].getALocalSource(), ["text/html", "text/x-amp-html"])
or
result = this.sendgridWrite("html_content")
or
exists(KeyValuePair content, Dict generalDict, KeyValuePair typePair, KeyValuePair valuePair |
content.getKey().(StrConst).getText() = "content" and
content.getValue().(List).getAnElt() = generalDict and
// declare KeyValuePairs keys and values
typePair.getKey().(StrConst).getText() = "type" and
typePair.getValue().(StrConst).getText() = ["text/html", "text/x-amp-html"] and
valuePair.getKey().(StrConst).getText() = "value" and
result.asExpr() = valuePair.getValue() and
// correlate generalDict with previously set KeyValuePairs
generalDict.getAnItem() in [typePair, valuePair] and
[this.getArg(0), this.getArgByName("request_body")].getALocalSource().asExpr() =
any(Dict d | d.getAnItem() = content)
)
or
exists(KeyValuePair footer, Dict generalDict, KeyValuePair enablePair, KeyValuePair htmlPair |
footer.getKey().(StrConst).getText() = ["footer", "subscription_tracking"] and
footer.getValue() = generalDict and
// check footer is enabled
enablePair.getKey().(StrConst).getText() = "enable" and
exists(enablePair.getValue().(True)) and
// get html content
htmlPair.getKey().(StrConst).getText() = "html" and
result.asExpr() = htmlPair.getValue() and
// correlate generalDict with previously set KeyValuePairs
generalDict.getAnItem() in [enablePair, htmlPair] and
exists(KeyValuePair k |
k.getKey() =
[this.getArg(0), this.getArgByName("request_body")]
.getALocalSource()
.asExpr()
.(Dict)
.getAKey() and
k.getValue() = any(Dict d | d.getAKey() = footer.getKey())
)
)
}
override DataFlow::Node getTo() {
result in [this.getMailCall().getArg(1), this.getMailCall().getArgByName("to_emails")]
or
result = this.getMailCall().getAMethodCall("To").getArg(0)
or
result =
this.getMailCall()
.getAMethodCall(["to", "add_to", "cc", "add_cc", "bcc", "add_bcc"])
.getArg(0)
}
override DataFlow::Node getFrom() {
result in [this.getMailCall().getArg(0), this.getMailCall().getArgByName("from_email")]
or
result = this.getMailCall().getAMethodCall("Email").getArg(0)
or
result = this.getMailCall().getAMethodCall(["from_email", "set_from"]).getArg(0)
or
result = this.sendgridWrite("from_email")
}
override DataFlow::Node getSubject() {
result in [this.getMailCall().getArg(2), this.getMailCall().getArgByName("subject")]
or
result = this.getMailCall().getAMethodCall(["subject", "set_subject"]).getArg(0)
or
result = this.sendgridWrite("subject")
}
}
}

Просмотреть файл

@ -0,0 +1,81 @@
/**
* Provides classes modeling security-relevant aspects of the `flask` PyPI package.
* See https://flask.palletsprojects.com/en/1.1.x/.
*/
private import python
private import semmle.python.dataflow.new.DataFlow
private import experimental.semmle.python.Concepts
private import semmle.python.ApiGraphs
/** https://pythonhosted.org/Flask-Mail/#module-flask_mail */
private module FlaskMail {
/** Gets a reference to `flask_mail`, `flask_sendmail` and `flask.ext.sendmail`. */
private API::Node flaskMail() {
result = API::moduleImport(["flask_mail", "flask_sendmail", "flask.ext.sendmail"])
}
/** Gets a reference to `flask_mail.Mail()`, `flask_sendmail.Mail()` and `flask.ext.sendmail.Mail()`. */
private API::Node flaskMailInstance() { result = flaskMail().getMember("Mail").getReturn() }
/**
* Gets a call to `mail.send()`.
*
* Given the following example:
*
* ```py
* msg = Message(subject="Subject",
* sender="from@example.com",
* recipients=["to@example.com"],
* body="plain-text body",
* html=request.args["html"])
* mail.send(msg)
* ```
*
* * `this` would be `mail.send(msg)`.
* * `getPlainTextBody()`'s result would be `"plain-text body"`.
* * `getHtmlBody()`'s result would be `request.args["html"]`.
* * `getTo()`'s result would be `["to@example.com"]`.
* * `getFrom()`'s result would be `"from@example.com"`.
* * `getSubject()`'s result would be `"Subject"`.
*/
private class FlaskMail extends DataFlow::CallCfgNode, EmailSender::Range {
FlaskMail() {
this =
[flaskMailInstance(), flaskMailInstance().getMember("connect").getReturn()]
.getMember(["send", "send_message"])
.getACall()
}
private DataFlow::CallCfgNode getMessage() { result = this.getArg(0).getALocalSource() }
bindingset[argumentPosition]
private DataFlow::Node getFlaskMailArgument(int argumentPosition, string argumentName) {
argumentPosition in [[0 .. 3], 5] and
argumentName in ["body", "html", "recipients", "sender", "subject"] and
result in [
this.getMessage().getArg(argumentPosition), this.getMessage().getArgByName(argumentName)
]
or
exists(DataFlow::AttrWrite write |
write.getObject().getALocalSource() = this.getMessage() and
write.getAttributeName() = argumentName and
result = write.getValue()
)
}
override DataFlow::Node getPlainTextBody() { result = this.getFlaskMailArgument(2, "body") }
override DataFlow::Node getHtmlBody() { result = this.getFlaskMailArgument(3, "html") }
override DataFlow::Node getTo() {
result = this.getFlaskMailArgument(1, "recipients")
or
result = this.getMessage().getAMethodCall("add_recipient").getACall().getArg(0)
}
override DataFlow::Node getFrom() { result = this.getFlaskMailArgument(5, "sender") }
override DataFlow::Node getSubject() { result = this.getFlaskMailArgument(0, "subject") }
}
}

Просмотреть файл

@ -0,0 +1,177 @@
private import python
private import semmle.python.dataflow.new.DataFlow
private import experimental.semmle.python.Concepts
private import semmle.python.ApiGraphs
private import semmle.python.dataflow.new.TaintTracking2
module SmtpLib {
/** Gets a reference to `smtplib.SMTP_SSL` */
private API::Node smtpConnectionInstance() {
result = API::moduleImport("smtplib").getMember("SMTP_SSL")
}
/** Gets a reference to `email.mime.multipart.MIMEMultipart` */
private API::Node smtpMimeMultipartInstance() {
result =
API::moduleImport("email").getMember("mime").getMember("multipart").getMember("MIMEMultipart")
}
/** Gets a reference to `email.mime.text.MIMEText` */
private API::Node smtpMimeTextInstance() {
result = API::moduleImport("email").getMember("mime").getMember("text").getMember("MIMEText")
}
private DataFlow::CallCfgNode mimeText(string mimetype) {
result = smtpMimeTextInstance().getACall() and
[result.getArg(1), result.getArgByName("_subtype")].asExpr().(StrConst).getText() = mimetype
}
/**
* Gets flow from `MIMEText()` to `MIMEMultipart(_subparts=(part1, part2))`'s `_subparts`
* argument. Used because of the impossibility to get local source nodes from `_subparts`'
* `(List|Tuple)` elements.
*/
private class SMTPMessageConfig extends TaintTracking2::Configuration {
SMTPMessageConfig() { this = "SMTPMessageConfig" }
override predicate isSource(DataFlow::Node source) { source = mimeText(_) }
override predicate isSink(DataFlow::Node sink) {
sink = smtpMimeMultipartInstance().getACall().getArgByName("_subparts")
}
}
/**
* Using the `MimeText` call retrieves the content argument whose type argument equals `mimetype`.
* This call flows into `MIMEMultipart`'s `_subparts` argument or the `.attach()` method call
* and both local source nodes correlate to `smtp`'s `sendmail` call 3rd argument's local source.
*
* Given the following example with `getSmtpMessage(any(SmtpLibSendMail s), "html")`:
*
* ```py
* part1 = MIMEText(text, "plain")
* part2 = MIMEText(html, "html")
* message = MIMEMultipart(_subparts=(part1, part2))
* server.sendmail(sender_email, receiver_email, message.as_string())
* ```
*
* * `source` would be `MIMEText(text, "html")`.
* * `sink` would be `MIMEMultipart(_subparts=(part1, part2))`.
* * Then `message` local source node is correlated to `sink`.
* * Then the flow from `source` to `_subparts` is checked.
*
* Given the following example with `getSmtpMessage(any(SmtpLibSendMail s), "html")`:
*
* ```py
* part1 = MIMEText(text, "plain")
* part2 = MIMEText(html, "html")
* message = MIMEMultipart("alternative")
* message.attach(part1)
* message.attach(part2)
* server.sendmail(sender_email, receiver_email, message.as_string())
* ```
*
* * `source` would be `MIMEText(text, "html")`.
* * `sink` would be `message.attach(part2)`.
* * Then `sink`'s object (`message`) local source is correlated to `server.sendmail`
* 3rd argument local source (`MIMEMultipart("alternative")`).
* * Then the flow from `source` to `sink` 1st argument is checked.
*/
bindingset[mimetype]
private DataFlow::Node getSmtpMessage(DataFlow::CallCfgNode sendCall, string mimetype) {
exists(DataFlow::Node source, DataFlow::Node sink |
source = mimeText(mimetype) and
(
// via _subparts
sink = smtpMimeMultipartInstance().getACall() and
sink =
[sendCall.getArg(2), sendCall.getArg(2).(DataFlow::MethodCallNode).getObject()]
.getALocalSource() and
any(SMTPMessageConfig a)
.hasFlow(source, sink.(DataFlow::CallCfgNode).getArgByName("_subparts"))
or
// via .attach()
sink = smtpMimeMultipartInstance().getReturn().getMember("attach").getACall() and
sink.(DataFlow::MethodCallNode).getObject().getALocalSource() =
[sendCall.getArg(2), sendCall.getArg(2).(DataFlow::MethodCallNode).getObject()]
.getALocalSource() and
source.(DataFlow::CallCfgNode).flowsTo(sink.(DataFlow::CallCfgNode).getArg(0))
) and
result = source.(DataFlow::CallCfgNode).getArg(0)
)
}
/**
* Gets a message subscript write by correlating subscript's object local source with
* `smtp`'s `sendmail` call 3rd argument's local source.
*
* Given the following example with `getSMTPSubscriptByIndex(any(SmtpLibSendMail s), "Subject")`:
*
* ```py
* message = MIMEMultipart("alternative")
* message["Subject"] = "multipart test"
* server.sendmail(sender_email, receiver_email, message.as_string())
* ```
*
* * `def` would be `message["Subject"]` (`DefinitionNode`)
* * `sub` would be `message["Subject"]` (`Subscript`)
* * `result` would be `"multipart test"`
*/
private DataFlow::Node getSMTPSubscriptByIndex(DataFlow::CallCfgNode sendCall, string index) {
exists(DefinitionNode def, Subscript sub |
sub = def.getNode() and
DataFlow::exprNode(sub.getObject()).getALocalSource() =
[sendCall.getArg(2), sendCall.getArg(2).(DataFlow::MethodCallNode).getObject()]
.getALocalSource() and
sub.getIndex().(StrConst).getText() = index and
result.asCfgNode() = def.getValue()
)
}
/**
* Gets a reference to `smtplib.SMTP_SSL().sendmail()`.
*
* Given the following example:
*
* ```py
* part1 = MIMEText(text, "plain")
* part2 = MIMEText(html, "html")
*
* message = MIMEMultipart(_subparts=(part1, part2))
* message["Subject"] = "multipart test"
* message["From"] = sender_email
* message["To"] = receiver_email
*
* server.login(sender_email, "SERVER_PASSWORD")
* server.sendmail(sender_email, receiver_email, message.as_string())
* ```
*
* * `this` would be `server.sendmail(sender_email, receiver_email, message.as_string())`.
* * `getPlainTextBody()`'s result would be `text`.
* * `getHtmlBody()`'s result would be `html`.
* * `getTo()`'s result would be `receiver_email`.
* * `getFrom()`'s result would be `sender_email`.
* * `getSubject()`'s result would be `"multipart test"`.
*/
private class SmtpLibSendMail extends DataFlow::CallCfgNode, EmailSender::Range {
SmtpLibSendMail() {
this = smtpConnectionInstance().getReturn().getMember("sendmail").getACall()
}
override DataFlow::Node getPlainTextBody() { result = getSmtpMessage(this, "plain") }
override DataFlow::Node getHtmlBody() { result = getSmtpMessage(this, "html") }
override DataFlow::Node getTo() {
result in [this.getArg(1), getSMTPSubscriptByIndex(this, "To")]
}
override DataFlow::Node getFrom() {
result in [this.getArg(0), getSMTPSubscriptByIndex(this, "From")]
}
override DataFlow::Node getSubject() {
result in [this.getArg(2), getSMTPSubscriptByIndex(this, "Subject")]
}
}
}

Просмотреть файл

@ -0,0 +1,46 @@
/**
* Provides a taint-tracking configuration for detecting reflected server-side
* cross-site scripting vulnerabilities.
*/
import python
import semmle.python.dataflow.new.DataFlow
import semmle.python.dataflow.new.TaintTracking
import semmle.python.dataflow.new.RemoteFlowSources
import semmle.python.dataflow.new.BarrierGuards
import experimental.semmle.python.Concepts
import semmle.python.Concepts
import semmle.python.ApiGraphs
/**
* A taint-tracking configuration for detecting reflected server-side cross-site
* scripting vulnerabilities.
*/
class ReflectedXssConfiguration extends TaintTracking::Configuration {
ReflectedXssConfiguration() { this = "ReflectedXssConfiguration" }
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
override predicate isSink(DataFlow::Node sink) { sink = any(EmailSender email).getHtmlBody() }
override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
guard instanceof StringConstCompare
}
override predicate isSanitizer(DataFlow::Node sanitizer) {
sanitizer = any(HtmlEscaping esc).getOutput()
}
override predicate isAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
exists(DataFlow::CallCfgNode htmlContentCall |
htmlContentCall =
API::moduleImport("sendgrid")
.getMember("helpers")
.getMember("mail")
.getMember("HtmlContent")
.getACall() and
nodeTo = htmlContentCall and
nodeFrom = htmlContentCall.getArg(0)
)
}
}

Просмотреть файл

@ -0,0 +1,96 @@
edges
| flask_mail.py:13:22:13:28 | ControlFlowNode for request | flask_mail.py:13:22:13:33 | ControlFlowNode for Attribute |
| flask_mail.py:13:22:13:28 | ControlFlowNode for request | flask_mail.py:18:14:18:25 | ControlFlowNode for Attribute |
| flask_mail.py:13:22:13:33 | ControlFlowNode for Attribute | flask_mail.py:13:22:13:41 | ControlFlowNode for Subscript |
| flask_mail.py:18:14:18:20 | ControlFlowNode for request | flask_mail.py:18:14:18:25 | ControlFlowNode for Attribute |
| flask_mail.py:18:14:18:25 | ControlFlowNode for Attribute | flask_mail.py:18:14:18:33 | ControlFlowNode for Subscript |
| flask_mail.py:31:24:31:30 | ControlFlowNode for request | flask_mail.py:31:24:31:35 | ControlFlowNode for Attribute |
| flask_mail.py:31:24:31:35 | ControlFlowNode for Attribute | flask_mail.py:31:24:31:43 | ControlFlowNode for Subscript |
| sendgrid_mail.py:14:22:14:28 | ControlFlowNode for request | sendgrid_mail.py:14:22:14:33 | ControlFlowNode for Attribute |
| sendgrid_mail.py:14:22:14:33 | ControlFlowNode for Attribute | sendgrid_mail.py:14:22:14:49 | ControlFlowNode for Subscript |
| sendgrid_mail.py:26:34:26:40 | ControlFlowNode for request | sendgrid_mail.py:26:34:26:45 | ControlFlowNode for Attribute |
| sendgrid_mail.py:26:34:26:45 | ControlFlowNode for Attribute | sendgrid_mail.py:26:34:26:61 | ControlFlowNode for Subscript |
| sendgrid_mail.py:26:34:26:61 | ControlFlowNode for Subscript | sendgrid_mail.py:26:22:26:62 | ControlFlowNode for HtmlContent() |
| sendgrid_mail.py:37:41:37:47 | ControlFlowNode for request | sendgrid_mail.py:37:41:37:52 | ControlFlowNode for Attribute |
| sendgrid_mail.py:37:41:37:52 | ControlFlowNode for Attribute | sendgrid_mail.py:37:41:37:68 | ControlFlowNode for Subscript |
| sendgrid_via_mail_send_post_request_body_bad.py:16:51:16:57 | ControlFlowNode for request | sendgrid_via_mail_send_post_request_body_bad.py:16:51:16:62 | ControlFlowNode for Attribute |
| sendgrid_via_mail_send_post_request_body_bad.py:16:51:16:57 | ControlFlowNode for request | sendgrid_via_mail_send_post_request_body_bad.py:27:50:27:61 | ControlFlowNode for Attribute |
| sendgrid_via_mail_send_post_request_body_bad.py:16:51:16:57 | ControlFlowNode for request | sendgrid_via_mail_send_post_request_body_bad.py:41:50:41:61 | ControlFlowNode for Attribute |
| sendgrid_via_mail_send_post_request_body_bad.py:16:51:16:62 | ControlFlowNode for Attribute | sendgrid_via_mail_send_post_request_body_bad.py:16:51:16:78 | ControlFlowNode for Subscript |
| sendgrid_via_mail_send_post_request_body_bad.py:16:51:16:78 | ControlFlowNode for Subscript | sendgrid_via_mail_send_post_request_body_bad.py:16:26:16:79 | ControlFlowNode for Attribute() |
| sendgrid_via_mail_send_post_request_body_bad.py:27:50:27:56 | ControlFlowNode for request | sendgrid_via_mail_send_post_request_body_bad.py:27:50:27:61 | ControlFlowNode for Attribute |
| sendgrid_via_mail_send_post_request_body_bad.py:27:50:27:56 | ControlFlowNode for request | sendgrid_via_mail_send_post_request_body_bad.py:41:50:41:61 | ControlFlowNode for Attribute |
| sendgrid_via_mail_send_post_request_body_bad.py:27:50:27:61 | ControlFlowNode for Attribute | sendgrid_via_mail_send_post_request_body_bad.py:27:50:27:76 | ControlFlowNode for Subscript |
| sendgrid_via_mail_send_post_request_body_bad.py:27:50:27:76 | ControlFlowNode for Subscript | sendgrid_via_mail_send_post_request_body_bad.py:27:25:27:77 | ControlFlowNode for Attribute() |
| sendgrid_via_mail_send_post_request_body_bad.py:41:50:41:56 | ControlFlowNode for request | sendgrid_via_mail_send_post_request_body_bad.py:41:50:41:61 | ControlFlowNode for Attribute |
| sendgrid_via_mail_send_post_request_body_bad.py:41:50:41:61 | ControlFlowNode for Attribute | sendgrid_via_mail_send_post_request_body_bad.py:41:50:41:78 | ControlFlowNode for Subscript |
| sendgrid_via_mail_send_post_request_body_bad.py:41:50:41:78 | ControlFlowNode for Subscript | sendgrid_via_mail_send_post_request_body_bad.py:41:25:41:79 | ControlFlowNode for Attribute() |
| smtplib_bad_subparts.py:17:12:17:18 | ControlFlowNode for request | smtplib_bad_subparts.py:17:12:17:23 | ControlFlowNode for Attribute |
| smtplib_bad_subparts.py:17:12:17:23 | ControlFlowNode for Attribute | smtplib_bad_subparts.py:17:12:17:33 | ControlFlowNode for Subscript |
| smtplib_bad_subparts.py:17:12:17:33 | ControlFlowNode for Subscript | smtplib_bad_subparts.py:24:22:24:25 | ControlFlowNode for html |
| smtplib_bad_via_attach.py:20:12:20:18 | ControlFlowNode for request | smtplib_bad_via_attach.py:20:12:20:23 | ControlFlowNode for Attribute |
| smtplib_bad_via_attach.py:20:12:20:23 | ControlFlowNode for Attribute | smtplib_bad_via_attach.py:20:12:20:31 | ControlFlowNode for Subscript |
| smtplib_bad_via_attach.py:20:12:20:31 | ControlFlowNode for Subscript | smtplib_bad_via_attach.py:27:22:27:25 | ControlFlowNode for html |
nodes
| django_mail.py:14:48:14:82 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
| django_mail.py:23:30:23:64 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
| django_mail.py:25:32:25:66 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
| flask_mail.py:13:22:13:28 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
| flask_mail.py:13:22:13:33 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
| flask_mail.py:13:22:13:41 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
| flask_mail.py:18:14:18:20 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
| flask_mail.py:18:14:18:25 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
| flask_mail.py:18:14:18:33 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
| flask_mail.py:31:24:31:30 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
| flask_mail.py:31:24:31:35 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
| flask_mail.py:31:24:31:43 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
| sendgrid_mail.py:14:22:14:28 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
| sendgrid_mail.py:14:22:14:33 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
| sendgrid_mail.py:14:22:14:49 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
| sendgrid_mail.py:26:22:26:62 | ControlFlowNode for HtmlContent() | semmle.label | ControlFlowNode for HtmlContent() |
| sendgrid_mail.py:26:34:26:40 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
| sendgrid_mail.py:26:34:26:45 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
| sendgrid_mail.py:26:34:26:61 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
| sendgrid_mail.py:37:41:37:47 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
| sendgrid_mail.py:37:41:37:52 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
| sendgrid_mail.py:37:41:37:68 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
| sendgrid_via_mail_send_post_request_body_bad.py:16:26:16:79 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
| sendgrid_via_mail_send_post_request_body_bad.py:16:51:16:57 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
| sendgrid_via_mail_send_post_request_body_bad.py:16:51:16:62 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
| sendgrid_via_mail_send_post_request_body_bad.py:16:51:16:78 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
| sendgrid_via_mail_send_post_request_body_bad.py:27:25:27:77 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
| sendgrid_via_mail_send_post_request_body_bad.py:27:50:27:56 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
| sendgrid_via_mail_send_post_request_body_bad.py:27:50:27:61 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
| sendgrid_via_mail_send_post_request_body_bad.py:27:50:27:76 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
| sendgrid_via_mail_send_post_request_body_bad.py:41:25:41:79 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
| sendgrid_via_mail_send_post_request_body_bad.py:41:50:41:56 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
| sendgrid_via_mail_send_post_request_body_bad.py:41:50:41:61 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
| sendgrid_via_mail_send_post_request_body_bad.py:41:50:41:78 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
| smtplib_bad_subparts.py:17:12:17:18 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
| smtplib_bad_subparts.py:17:12:17:23 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
| smtplib_bad_subparts.py:17:12:17:33 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
| smtplib_bad_subparts.py:24:22:24:25 | ControlFlowNode for html | semmle.label | ControlFlowNode for html |
| smtplib_bad_via_attach.py:20:12:20:18 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
| smtplib_bad_via_attach.py:20:12:20:23 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
| smtplib_bad_via_attach.py:20:12:20:31 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
| smtplib_bad_via_attach.py:27:22:27:25 | ControlFlowNode for html | semmle.label | ControlFlowNode for html |
subpaths
#select
| django_mail.py:14:48:14:82 | ControlFlowNode for Attribute() | django_mail.py:14:48:14:82 | ControlFlowNode for Attribute() | django_mail.py:14:48:14:82 | ControlFlowNode for Attribute() | Cross-site scripting vulnerability due to $@. | django_mail.py:14:48:14:82 | ControlFlowNode for Attribute() | a user-provided value |
| django_mail.py:23:30:23:64 | ControlFlowNode for Attribute() | django_mail.py:23:30:23:64 | ControlFlowNode for Attribute() | django_mail.py:23:30:23:64 | ControlFlowNode for Attribute() | Cross-site scripting vulnerability due to $@. | django_mail.py:23:30:23:64 | ControlFlowNode for Attribute() | a user-provided value |
| django_mail.py:25:32:25:66 | ControlFlowNode for Attribute() | django_mail.py:25:32:25:66 | ControlFlowNode for Attribute() | django_mail.py:25:32:25:66 | ControlFlowNode for Attribute() | Cross-site scripting vulnerability due to $@. | django_mail.py:25:32:25:66 | ControlFlowNode for Attribute() | a user-provided value |
| flask_mail.py:13:22:13:41 | ControlFlowNode for Subscript | flask_mail.py:13:22:13:28 | ControlFlowNode for request | flask_mail.py:13:22:13:41 | ControlFlowNode for Subscript | Cross-site scripting vulnerability due to $@. | flask_mail.py:13:22:13:28 | ControlFlowNode for request | a user-provided value |
| flask_mail.py:18:14:18:33 | ControlFlowNode for Subscript | flask_mail.py:13:22:13:28 | ControlFlowNode for request | flask_mail.py:18:14:18:33 | ControlFlowNode for Subscript | Cross-site scripting vulnerability due to $@. | flask_mail.py:13:22:13:28 | ControlFlowNode for request | a user-provided value |
| flask_mail.py:18:14:18:33 | ControlFlowNode for Subscript | flask_mail.py:18:14:18:20 | ControlFlowNode for request | flask_mail.py:18:14:18:33 | ControlFlowNode for Subscript | Cross-site scripting vulnerability due to $@. | flask_mail.py:18:14:18:20 | ControlFlowNode for request | a user-provided value |
| flask_mail.py:31:24:31:43 | ControlFlowNode for Subscript | flask_mail.py:31:24:31:30 | ControlFlowNode for request | flask_mail.py:31:24:31:43 | ControlFlowNode for Subscript | Cross-site scripting vulnerability due to $@. | flask_mail.py:31:24:31:30 | ControlFlowNode for request | a user-provided value |
| sendgrid_mail.py:14:22:14:49 | ControlFlowNode for Subscript | sendgrid_mail.py:14:22:14:28 | ControlFlowNode for request | sendgrid_mail.py:14:22:14:49 | ControlFlowNode for Subscript | Cross-site scripting vulnerability due to $@. | sendgrid_mail.py:14:22:14:28 | ControlFlowNode for request | a user-provided value |
| sendgrid_mail.py:26:22:26:62 | ControlFlowNode for HtmlContent() | sendgrid_mail.py:26:34:26:40 | ControlFlowNode for request | sendgrid_mail.py:26:22:26:62 | ControlFlowNode for HtmlContent() | Cross-site scripting vulnerability due to $@. | sendgrid_mail.py:26:34:26:40 | ControlFlowNode for request | a user-provided value |
| sendgrid_mail.py:37:41:37:68 | ControlFlowNode for Subscript | sendgrid_mail.py:37:41:37:47 | ControlFlowNode for request | sendgrid_mail.py:37:41:37:68 | ControlFlowNode for Subscript | Cross-site scripting vulnerability due to $@. | sendgrid_mail.py:37:41:37:47 | ControlFlowNode for request | a user-provided value |
| sendgrid_via_mail_send_post_request_body_bad.py:16:26:16:79 | ControlFlowNode for Attribute() | sendgrid_via_mail_send_post_request_body_bad.py:16:51:16:57 | ControlFlowNode for request | sendgrid_via_mail_send_post_request_body_bad.py:16:26:16:79 | ControlFlowNode for Attribute() | Cross-site scripting vulnerability due to $@. | sendgrid_via_mail_send_post_request_body_bad.py:16:51:16:57 | ControlFlowNode for request | a user-provided value |
| sendgrid_via_mail_send_post_request_body_bad.py:27:25:27:77 | ControlFlowNode for Attribute() | sendgrid_via_mail_send_post_request_body_bad.py:16:51:16:57 | ControlFlowNode for request | sendgrid_via_mail_send_post_request_body_bad.py:27:25:27:77 | ControlFlowNode for Attribute() | Cross-site scripting vulnerability due to $@. | sendgrid_via_mail_send_post_request_body_bad.py:16:51:16:57 | ControlFlowNode for request | a user-provided value |
| sendgrid_via_mail_send_post_request_body_bad.py:27:25:27:77 | ControlFlowNode for Attribute() | sendgrid_via_mail_send_post_request_body_bad.py:27:50:27:56 | ControlFlowNode for request | sendgrid_via_mail_send_post_request_body_bad.py:27:25:27:77 | ControlFlowNode for Attribute() | Cross-site scripting vulnerability due to $@. | sendgrid_via_mail_send_post_request_body_bad.py:27:50:27:56 | ControlFlowNode for request | a user-provided value |
| sendgrid_via_mail_send_post_request_body_bad.py:41:25:41:79 | ControlFlowNode for Attribute() | sendgrid_via_mail_send_post_request_body_bad.py:16:51:16:57 | ControlFlowNode for request | sendgrid_via_mail_send_post_request_body_bad.py:41:25:41:79 | ControlFlowNode for Attribute() | Cross-site scripting vulnerability due to $@. | sendgrid_via_mail_send_post_request_body_bad.py:16:51:16:57 | ControlFlowNode for request | a user-provided value |
| sendgrid_via_mail_send_post_request_body_bad.py:41:25:41:79 | ControlFlowNode for Attribute() | sendgrid_via_mail_send_post_request_body_bad.py:27:50:27:56 | ControlFlowNode for request | sendgrid_via_mail_send_post_request_body_bad.py:41:25:41:79 | ControlFlowNode for Attribute() | Cross-site scripting vulnerability due to $@. | sendgrid_via_mail_send_post_request_body_bad.py:27:50:27:56 | ControlFlowNode for request | a user-provided value |
| sendgrid_via_mail_send_post_request_body_bad.py:41:25:41:79 | ControlFlowNode for Attribute() | sendgrid_via_mail_send_post_request_body_bad.py:41:50:41:56 | ControlFlowNode for request | sendgrid_via_mail_send_post_request_body_bad.py:41:25:41:79 | ControlFlowNode for Attribute() | Cross-site scripting vulnerability due to $@. | sendgrid_via_mail_send_post_request_body_bad.py:41:50:41:56 | ControlFlowNode for request | a user-provided value |
| smtplib_bad_subparts.py:24:22:24:25 | ControlFlowNode for html | smtplib_bad_subparts.py:17:12:17:18 | ControlFlowNode for request | smtplib_bad_subparts.py:24:22:24:25 | ControlFlowNode for html | Cross-site scripting vulnerability due to $@. | smtplib_bad_subparts.py:17:12:17:18 | ControlFlowNode for request | a user-provided value |
| smtplib_bad_via_attach.py:27:22:27:25 | ControlFlowNode for html | smtplib_bad_via_attach.py:20:12:20:18 | ControlFlowNode for request | smtplib_bad_via_attach.py:27:22:27:25 | ControlFlowNode for html | Cross-site scripting vulnerability due to $@. | smtplib_bad_via_attach.py:20:12:20:18 | ControlFlowNode for request | a user-provided value |

Просмотреть файл

@ -0,0 +1 @@
experimental/Security/CWE-079/ReflectedXSS.ql

Просмотреть файл

@ -0,0 +1,25 @@
import django.http
from django.core.mail import send_mail, mail_admins, mail_managers
def django_response(request):
"""
The Django.core.mail#send_mail function source code can be found in the link below:
https://github.com/django/django/blob/ca9872905559026af82000e46cde6f7dedc897b6/django/core/mail/__init__.py#L38
send_mass_mail does not provide html_message as an argument to it's function. See the link below for more info:
https://github.com/django/django/blob/ca9872905559026af82000e46cde6f7dedc897b6/django/core/mail/__init__.py#L64
"""
send_mail("Subject", "plain-text body", "from@example.com",
["to@example.com"], html_message=django.http.request.GET.get("html"))
def django_response(request):
"""
The Django.core.mail#mail_admins and Django.core.mail#mail_managers functions source code can be found in the link below:
https://github.com/django/django/blob/ca9872905559026af82000e46cde6f7dedc897b6/django/core/mail/__init__.py#L90-L121
"""
mail_admins("Subject", "plain-text body",
html_message=django.http.request.GET.get("html"))
mail_managers("Subject", "plain-text body",
html_message=django.http.request.GET.get("html"))

Просмотреть файл

@ -0,0 +1,32 @@
from flask import request, Flask
from flask_mail import Mail, Message
app = Flask(__name__)
mail = Mail(app)
@app.route("/send")
def send():
msg = Message(subject="Subject",
sender="from@example.com",
recipients=["to@example.com"],
body="plain-text body",
html=request.args["html"])
# The message can contain a body and/or HTML:
msg.body = "plain-text body"
# The email's HTML can be set via msg.html or as an initialize argument when creating a Message object.
msg.html = request.args["html"]
mail.send(msg)
@app.route("/connect")
def connect():
"""
Minimal example to test mail.connect() usage
"""
with mail.connect() as conn:
msg = Message(subject="Subject",
sender="from@example.com",
recipients=["to@example.com"],
html=request.args["html"])
conn.send(msg)

Просмотреть файл

@ -0,0 +1,57 @@
from flask import request, Flask
from sendgrid import SendGridAPIClient
from sendgrid.helpers.mail import Mail, Email, To, Content, MimeType, HtmlContent
app = Flask(__name__)
@app.route("/send")
def send():
message = Mail(
from_email='from_email@example.com',
to_emails='to@example.com',
subject='Sending with Twilio SendGrid is Fun',
html_content=request.args["html_content"])
sg = SendGridAPIClient('SENDGRID_API_KEY')
sg.send(message)
@app.route("/send-HtmlContent")
def send():
message = Mail(
from_email='from_email@example.com',
to_emails='to@example.com',
subject='Sending with Twilio SendGrid is Fun',
html_content=HtmlContent(request.args["html_content"]))
sg = SendGridAPIClient('SENDGRID_API_KEY')
sg.send(message)
@app.route("/send_post")
def send_post():
from_email = Email("test@example.com")
to_email = To("test@example.com")
subject = "Sending with SendGrid is Fun"
html_content = Content("text/html", request.args["html_content"])
plain_content = Content("text/plain", request.args["plain_content"])
mail = Mail(from_email, to_email, subject, plain_content, html_content)
sg = SendGridAPIClient(api_key='SENDGRID_API_KEY')
response = sg.client.mail.send.post(request_body=mail.get())
@app.route("/send_post2")
def send_post2():
from_email = Email("test@example.com")
to_email = To("test@example.com")
subject = "Sending with SendGrid is Fun"
html_content = Content(MimeType.html, request.args["html_content"])
plain_content = Content(MimeType.text, request.args["plain_content"])
mail = Mail(from_email, to_email, subject, plain_content, html_content)
sg = SendGridAPIClient(api_key='SENDGRID_API_KEY')
response = sg.client.mail.send.post(request_body=mail.get())

Просмотреть файл

@ -0,0 +1,48 @@
import sendgrid
import os
from flask import request, Flask
app = Flask(__name__)
@app.route("/sendgrid")
def send():
sg = sendgrid.SendGridAPIClient(os.environ.get('SENDGRID_API_KEY'))
data = {
"content": [
{
"type": "text/html",
"value": "<html>{}</html>".format(request.args["html_content"])
}
],
"from": {
"email": "sam.smith@example.com",
"name": "Sam Smith"
},
"headers": {},
"mail_settings": {
"footer": {
"enable": True,
"html": "<html>{}</html>".format(request.args["html_footer"]),
"text": "Thanks,/n The SendGrid Team"
},
},
"reply_to": {
"email": "sam.smith@example.com",
"name": "Sam Smith"
},
"send_at": 1409348513,
"subject": "Hello, World!",
"template_id": "[YOUR TEMPLATE ID GOES HERE]",
"tracking_settings": {
"subscription_tracking": {
"enable": True,
"html": "<html>{}</html>".format(request.args["html_tracking"]),
"substitution_tag": "<%click here%>",
"text": "If you would like to unsubscribe and stop receiving these emails <% click here %>."
}
}
}
response = sg.client.mail.send.post(request_body=data)

Просмотреть файл

@ -0,0 +1,42 @@
# This test checks that the developer doesn't pass a MIMEText instance to a MIMEMultipart initializer via the subparts parameter.
from flask import Flask, request
import json
import smtplib
import ssl
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
app = Flask(__name__)
@app.route("/")
def email_person():
sender_email = "sender@gmail.com"
receiver_email = "receiver@example.com"
name = request.args['search']
# Create the plain-text and HTML version of your message
text = "hello there"
html = f"hello {name}"
# Turn these into plain/html MIMEText objects
part1 = MIMEText(text, "plain")
part2 = MIMEText(html, "html")
message = MIMEMultipart(_subparts=(part1, part2))
message["Subject"] = "multipart test"
message["From"] = sender_email
message["To"] = receiver_email
# Create secure connection with server and send email
context = ssl.create_default_context()
server = smtplib.SMTP_SSL("smtp.gmail.com", 465, context=context)
server.login(sender_email, "SERVER_PASSWORD")
server.sendmail(
sender_email, receiver_email, message.as_string()
)
# if __name__ == "__main__":
# app.run(debug=True)

Просмотреть файл

@ -0,0 +1,45 @@
# This test checks that the developer doesn't pass a MIMEText instance to a MIMEMultipart message.
from flask import Flask, request
import json
import smtplib, ssl
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
app = Flask(__name__)
@app.route("/")
def email_person():
sender_email = "sender@gmail.com"
receiver_email = "receiver@example.com"
message = MIMEMultipart("alternative")
message["Subject"] = "multipart test"
message["From"] = sender_email
message["To"] = receiver_email
name = request.args['name']
# Create the plain-text and HTML version of your message
text = "hello there"
html = f"hello {name}"
# Turn these into plain/html MIMEText objects
part1 = MIMEText(text, "plain")
part2 = MIMEText(html, "html")
# Add HTML/plain-text parts to MIMEMultipart message
# The email client will try to render the last part first
message.attach(part1)
message.attach(part2)
# Create secure connection with server and send email
context = ssl.create_default_context()
server = smtplib.SMTP_SSL("smtp.gmail.com", 465, context=context)
server.login(sender_email, "SERVER_PASSWORD")
server.sendmail(
sender_email, receiver_email, message.as_string()
)
# if __name__ == "__main__":
# app.run(debug=True)