-
Notifications
You must be signed in to change notification settings - Fork 2k
Expand file tree
/
Copy pathEmail.qll
More file actions
107 lines (97 loc) · 4.03 KB
/
Email.qll
File metadata and controls
107 lines (97 loc) · 4.03 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
/** Provides classes for working with email-related APIs. */
overlay[local?]
module;
import go
/**
* A data-flow node that represents data written to an email, either as part
* of the headers or as part of the body.
*
* Extend this class to refine existing API models. If you want to model new APIs,
* extend `EmailData::Range` instead.
*/
class EmailData extends DataFlow::Node instanceof EmailData::Range { }
/** Provides classes for working with data that is incorporated into an email. */
module EmailData {
/**
* A data-flow node that represents data which is written to an email, either as part
* of the headers or as part of the body.
*
* Extend this class to model new APIs. If you want to refine existing API models,
* extend `EmailData` instead.
*/
abstract class Range extends DataFlow::Node { }
/** A data-flow node that is written to an email using the net/smtp package. */
private class SmtpData extends Range {
SmtpData() {
// func (c *Client) Data() (io.WriteCloser, error)
exists(Method data, DataFlow::Node n |
data.hasQualifiedName("net/smtp", "Client", "Data") and
// Deal with cases like
// w, _ := s.Data()
// io.WriteString(w, source()) // $ Alert
// w.Write(source()) // $ Alert
DataFlow::localFlow(data.getACall().getResult(0), n) and
this.(DataFlow::PostUpdateNode).getPreUpdateNode() = n
)
or
// func SendMail(addr string, a Auth, from string, to []string, msg []byte) error
exists(Function sendMail |
sendMail.hasQualifiedName("net/smtp", "SendMail") and
this = sendMail.getACall().getArgument(4)
)
}
}
/** Gets the package name `github.com/sendgrid/sendgrid-go/helpers/mail`. */
private string sendgridMail() {
result = package("github.com/sendgrid/sendgrid-go", "helpers/mail")
}
/** A data-flow node that is written to an email using the sendgrid/sendgrid-go package. */
private class SendGridEmail extends Range {
SendGridEmail() {
// func NewSingleEmail(from *Email, subject string, to *Email, plainTextContent string, htmlContent string) *SGMailV3
exists(Function newSingleEmail |
newSingleEmail.hasQualifiedName(sendgridMail(), "NewSingleEmail") and
this = newSingleEmail.getACall().getArgument([1, 3, 4])
)
or
// func NewV3MailInit(from *Email, subject string, to *Email, content ...*Content) *SGMailV3
exists(Function newv3MailInit |
newv3MailInit.hasQualifiedName(sendgridMail(), "NewV3MailInit") and
this = newv3MailInit.getACall().getSyntacticArgument(any(int i | i = 1 or i >= 3))
)
or
// func (s *SGMailV3) AddContent(c ...*Content) *SGMailV3
exists(Method addContent |
addContent.hasQualifiedName(sendgridMail(), "SGMailV3", "AddContent") and
this = addContent.getACall().getASyntacticArgument()
)
}
}
}
// These models are not implemented using Models-as-Data because they represent reverse flow.
/**
* A taint model of the `Writer.CreatePart` method from `mime/multipart`.
*
* If tainted data is written to the multipart section created by this method, the underlying writer
* should be considered tainted as well.
*/
private class MultipartWriterCreatePartModel extends TaintTracking::FunctionModel, Method {
MultipartWriterCreatePartModel() {
this.hasQualifiedName("mime/multipart", "Writer", "CreatePart")
}
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
input.isResult(0) and output.isReceiver()
}
}
/**
* A taint model of the `NewWriter` function from `mime/multipart`.
*
* If tainted data is written to the writer created by this function, the underlying writer
* should be considered tainted as well.
*/
private class MultipartNewWriterModel extends TaintTracking::FunctionModel {
MultipartNewWriterModel() { this.hasQualifiedName("mime/multipart", "NewWriter") }
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
input.isResult() and output.isParameter(0)
}
}