зеркало из https://github.com/github/codeql.git
Merge pull request #7127 from jty-team/jty/python/emailInjection
Python: CWE-079 - Add Email injection query
This commit is contained in:
Коммит
699761889d
|
@ -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)
|
Загрузка…
Ссылка в новой задаче