Skip to content

Commit bde1bb4

Browse files
authored
Merge pull request github#6126 from erik-krogh/dates
Approved by esbena
2 parents eb95dff + c736606 commit bde1bb4

File tree

5 files changed

+390
-0
lines changed

5 files changed

+390
-0
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
lgtm,codescanning
2+
* Improved support for date parsing libraries, resulting in more results in security queries.
3+
Affected packages are
4+
[dayjs](https://npmjs.com/package/dayjs),
5+
[luxon](https://npmjs.com/package/luxon),
6+
[@date-io/moment](https://npmjs.com/package/@date-io/moment),
7+
[@date-io/luxon](https://npmjs.com/package/@date-io/luxon),
8+
[@date-io/dayjs](https://npmjs.com/package/@date-io/dayjs)
9+

javascript/ql/src/semmle/javascript/frameworks/DateFunctions.qll

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,14 +53,111 @@ private module DateFns {
5353
}
5454
}
5555

56+
/**
57+
* Provides classes and predicates modelling the `@date-io` libraries.
58+
*/
59+
private module DateIO {
60+
private class FormatStep extends TaintTracking::SharedTaintStep {
61+
override predicate stringManipulationStep(DataFlow::Node pred, DataFlow::Node succ) {
62+
exists(API::CallNode formatCall |
63+
formatCall =
64+
API::moduleImport("@date-io/" +
65+
["date-fns", "moment", "luxon", "dayjs", "date-fns-jalali", "jalaali", "hijri"])
66+
.getInstance()
67+
// the `format` function only select between a predefined list of formats, but the `formatByString` function formats using any string.
68+
.getMember(["formatByString", "formatNumber"])
69+
.getACall()
70+
|
71+
pred = formatCall.getArgument(1) and
72+
succ = formatCall
73+
)
74+
}
75+
}
76+
77+
/** Gets a method name from an `@date-io` adapter that returns an instance of the adapted library. */
78+
private string getAnAdapterMethodName() {
79+
result =
80+
[
81+
"addSeconds", "addMinutes", "addHours", "addDays", "addWeeks", "addMonths", "endOfDay",
82+
"setHours", "setMinutes", "setSeconds", "startOfMonth", "endOfMonth", "startOfWeek",
83+
"endOfWeek", "setYear", "date", "parse", "setMonth", "getNextMonth", "getPreviousMonth"
84+
]
85+
}
86+
87+
/**
88+
* Gets an instance of `library` that has been created by an `@date-io` adapter.
89+
* Library is one of: "moment", "luxon", or "dayjs".
90+
*/
91+
API::Node getAnAdaptedInstance(string library) {
92+
exists(API::Node adapter |
93+
library = "moment" and
94+
adapter = API::moduleImport("@date-io/moment")
95+
or
96+
library = "luxon" and
97+
adapter = API::moduleImport("@date-io/luxon")
98+
or
99+
library = "dayjs" and
100+
adapter = API::moduleImport("@date-io/dayjs")
101+
|
102+
result = adapter.getInstance().getMember(getAnAdapterMethodName()).getReturn()
103+
)
104+
}
105+
}
106+
107+
/**
108+
* Provides classes and predicates modelling the `luxon` library.
109+
*/
110+
private module Luxon {
111+
/**
112+
* Gets a reference to a `DateTime` object from the `luxon` library.
113+
*/
114+
private API::Node luxonDateTime() {
115+
exists(API::Node constructor | constructor = API::moduleImport("luxon").getMember("DateTime") |
116+
result = constructor.getInstance()
117+
or
118+
result =
119+
constructor
120+
.getMember([
121+
"fromJSDate", "fromJSDate", "fromISO", "now", "fromMillis", "fromHTTP",
122+
"fromObject", "fromRFC2822", "fromSeconds", "fromSQL", "fromFormat", "fromString",
123+
"invalid", "local", "utc"
124+
])
125+
.getReturn()
126+
or
127+
// fluent API that return immutable objects
128+
result = luxonDateTime().getAMember()
129+
or
130+
result = luxonDateTime().getReturn()
131+
or
132+
result = DateIO::getAnAdaptedInstance("luxon")
133+
)
134+
}
135+
136+
/**
137+
* A step of the form: `f -> luxonDateTime.toFormat(f)`.
138+
*/
139+
private class ToFormatStep extends TaintTracking::SharedTaintStep {
140+
override predicate stringManipulationStep(DataFlow::Node pred, DataFlow::Node succ) {
141+
exists(API::CallNode call | call = luxonDateTime().getMember("toFormat").getACall() |
142+
pred = call.getArgument(0) and succ = call
143+
)
144+
}
145+
}
146+
}
147+
56148
private module Moment {
57149
/** Gets a reference to a `moment` object. */
58150
private API::Node moment() {
59151
result = API::moduleImport(["moment", "moment-timezone"])
60152
or
153+
// `dayjs` largely has a similar API to `moment`
154+
result = API::moduleImport("dayjs")
155+
or
61156
result = moment().getReturn()
62157
or
63158
result = moment().getAMember()
159+
or
160+
result = DateIO::getAnAdaptedInstance(["moment", "dayjs"])
64161
}
65162

66163
/**

javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/Xss.expected

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,65 @@ nodes
126126
| dates.js:18:31:18:66 | `Time i ... aint)}` |
127127
| dates.js:18:42:18:64 | datefor ... taint) |
128128
| dates.js:18:59:18:63 | taint |
129+
| dates.js:21:31:21:68 | `Time i ... aint)}` |
130+
| dates.js:21:31:21:68 | `Time i ... aint)}` |
131+
| dates.js:21:42:21:66 | dayjs(t ... (taint) |
132+
| dates.js:21:61:21:65 | taint |
133+
| dates.js:30:9:30:69 | taint |
134+
| dates.js:30:17:30:69 | decodeU ... ing(1)) |
135+
| dates.js:30:36:30:55 | window.location.hash |
136+
| dates.js:30:36:30:55 | window.location.hash |
137+
| dates.js:30:36:30:68 | window. ... ring(1) |
138+
| dates.js:37:31:37:84 | `Time i ... aint)}` |
139+
| dates.js:37:31:37:84 | `Time i ... aint)}` |
140+
| dates.js:37:42:37:82 | dateFns ... taint) |
141+
| dates.js:37:77:37:81 | taint |
142+
| dates.js:38:31:38:84 | `Time i ... aint)}` |
143+
| dates.js:38:31:38:84 | `Time i ... aint)}` |
144+
| dates.js:38:42:38:82 | luxon.f ... taint) |
145+
| dates.js:38:77:38:81 | taint |
146+
| dates.js:39:31:39:86 | `Time i ... aint)}` |
147+
| dates.js:39:31:39:86 | `Time i ... aint)}` |
148+
| dates.js:39:42:39:84 | moment. ... taint) |
149+
| dates.js:39:79:39:83 | taint |
150+
| dates.js:40:31:40:84 | `Time i ... aint)}` |
151+
| dates.js:40:31:40:84 | `Time i ... aint)}` |
152+
| dates.js:40:42:40:82 | dayjs.f ... taint) |
153+
| dates.js:40:77:40:81 | taint |
154+
| dates.js:46:9:46:69 | taint |
155+
| dates.js:46:17:46:69 | decodeU ... ing(1)) |
156+
| dates.js:46:36:46:55 | window.location.hash |
157+
| dates.js:46:36:46:55 | window.location.hash |
158+
| dates.js:46:36:46:68 | window. ... ring(1) |
159+
| dates.js:48:31:48:90 | `Time i ... aint)}` |
160+
| dates.js:48:31:48:90 | `Time i ... aint)}` |
161+
| dates.js:48:42:48:88 | DateTim ... (taint) |
162+
| dates.js:48:83:48:87 | taint |
163+
| dates.js:49:31:49:89 | `Time i ... aint)}` |
164+
| dates.js:49:31:49:89 | `Time i ... aint)}` |
165+
| dates.js:49:42:49:87 | new Dat ... (taint) |
166+
| dates.js:49:82:49:86 | taint |
167+
| dates.js:50:31:50:104 | `Time i ... aint)}` |
168+
| dates.js:50:31:50:104 | `Time i ... aint)}` |
169+
| dates.js:50:42:50:102 | DateTim ... (taint) |
170+
| dates.js:50:97:50:101 | taint |
171+
| dates.js:54:9:54:69 | taint |
172+
| dates.js:54:17:54:69 | decodeU ... ing(1)) |
173+
| dates.js:54:36:54:55 | window.location.hash |
174+
| dates.js:54:36:54:55 | window.location.hash |
175+
| dates.js:54:36:54:68 | window. ... ring(1) |
176+
| dates.js:57:31:57:101 | `Time i ... aint)}` |
177+
| dates.js:57:31:57:101 | `Time i ... aint)}` |
178+
| dates.js:57:42:57:99 | moment. ... (taint) |
179+
| dates.js:57:94:57:98 | taint |
180+
| dates.js:59:31:59:87 | `Time i ... aint)}` |
181+
| dates.js:59:31:59:87 | `Time i ... aint)}` |
182+
| dates.js:59:42:59:85 | luxon.e ... (taint) |
183+
| dates.js:59:80:59:84 | taint |
184+
| dates.js:61:31:61:88 | `Time i ... aint)}` |
185+
| dates.js:61:31:61:88 | `Time i ... aint)}` |
186+
| dates.js:61:42:61:86 | dayjs.s ... (taint) |
187+
| dates.js:61:81:61:85 | taint |
129188
| event-handler-receiver.js:2:31:2:83 | '<h2><a ... ></h2>' |
130189
| event-handler-receiver.js:2:31:2:83 | '<h2><a ... ></h2>' |
131190
| event-handler-receiver.js:2:49:2:61 | location.href |
@@ -755,6 +814,7 @@ edges
755814
| dates.js:9:9:9:69 | taint | dates.js:13:59:13:63 | taint |
756815
| dates.js:9:9:9:69 | taint | dates.js:16:62:16:66 | taint |
757816
| dates.js:9:9:9:69 | taint | dates.js:18:59:18:63 | taint |
817+
| dates.js:9:9:9:69 | taint | dates.js:21:61:21:65 | taint |
758818
| dates.js:9:17:9:69 | decodeU ... ing(1)) | dates.js:9:9:9:69 | taint |
759819
| dates.js:9:36:9:55 | window.location.hash | dates.js:9:36:9:68 | window. ... ring(1) |
760820
| dates.js:9:36:9:55 | window.location.hash | dates.js:9:36:9:68 | window. ... ring(1) |
@@ -774,6 +834,61 @@ edges
774834
| dates.js:18:42:18:64 | datefor ... taint) | dates.js:18:31:18:66 | `Time i ... aint)}` |
775835
| dates.js:18:42:18:64 | datefor ... taint) | dates.js:18:31:18:66 | `Time i ... aint)}` |
776836
| dates.js:18:59:18:63 | taint | dates.js:18:42:18:64 | datefor ... taint) |
837+
| dates.js:21:42:21:66 | dayjs(t ... (taint) | dates.js:21:31:21:68 | `Time i ... aint)}` |
838+
| dates.js:21:42:21:66 | dayjs(t ... (taint) | dates.js:21:31:21:68 | `Time i ... aint)}` |
839+
| dates.js:21:61:21:65 | taint | dates.js:21:42:21:66 | dayjs(t ... (taint) |
840+
| dates.js:30:9:30:69 | taint | dates.js:37:77:37:81 | taint |
841+
| dates.js:30:9:30:69 | taint | dates.js:38:77:38:81 | taint |
842+
| dates.js:30:9:30:69 | taint | dates.js:39:79:39:83 | taint |
843+
| dates.js:30:9:30:69 | taint | dates.js:40:77:40:81 | taint |
844+
| dates.js:30:17:30:69 | decodeU ... ing(1)) | dates.js:30:9:30:69 | taint |
845+
| dates.js:30:36:30:55 | window.location.hash | dates.js:30:36:30:68 | window. ... ring(1) |
846+
| dates.js:30:36:30:55 | window.location.hash | dates.js:30:36:30:68 | window. ... ring(1) |
847+
| dates.js:30:36:30:68 | window. ... ring(1) | dates.js:30:17:30:69 | decodeU ... ing(1)) |
848+
| dates.js:37:42:37:82 | dateFns ... taint) | dates.js:37:31:37:84 | `Time i ... aint)}` |
849+
| dates.js:37:42:37:82 | dateFns ... taint) | dates.js:37:31:37:84 | `Time i ... aint)}` |
850+
| dates.js:37:77:37:81 | taint | dates.js:37:42:37:82 | dateFns ... taint) |
851+
| dates.js:38:42:38:82 | luxon.f ... taint) | dates.js:38:31:38:84 | `Time i ... aint)}` |
852+
| dates.js:38:42:38:82 | luxon.f ... taint) | dates.js:38:31:38:84 | `Time i ... aint)}` |
853+
| dates.js:38:77:38:81 | taint | dates.js:38:42:38:82 | luxon.f ... taint) |
854+
| dates.js:39:42:39:84 | moment. ... taint) | dates.js:39:31:39:86 | `Time i ... aint)}` |
855+
| dates.js:39:42:39:84 | moment. ... taint) | dates.js:39:31:39:86 | `Time i ... aint)}` |
856+
| dates.js:39:79:39:83 | taint | dates.js:39:42:39:84 | moment. ... taint) |
857+
| dates.js:40:42:40:82 | dayjs.f ... taint) | dates.js:40:31:40:84 | `Time i ... aint)}` |
858+
| dates.js:40:42:40:82 | dayjs.f ... taint) | dates.js:40:31:40:84 | `Time i ... aint)}` |
859+
| dates.js:40:77:40:81 | taint | dates.js:40:42:40:82 | dayjs.f ... taint) |
860+
| dates.js:46:9:46:69 | taint | dates.js:48:83:48:87 | taint |
861+
| dates.js:46:9:46:69 | taint | dates.js:49:82:49:86 | taint |
862+
| dates.js:46:9:46:69 | taint | dates.js:50:97:50:101 | taint |
863+
| dates.js:46:17:46:69 | decodeU ... ing(1)) | dates.js:46:9:46:69 | taint |
864+
| dates.js:46:36:46:55 | window.location.hash | dates.js:46:36:46:68 | window. ... ring(1) |
865+
| dates.js:46:36:46:55 | window.location.hash | dates.js:46:36:46:68 | window. ... ring(1) |
866+
| dates.js:46:36:46:68 | window. ... ring(1) | dates.js:46:17:46:69 | decodeU ... ing(1)) |
867+
| dates.js:48:42:48:88 | DateTim ... (taint) | dates.js:48:31:48:90 | `Time i ... aint)}` |
868+
| dates.js:48:42:48:88 | DateTim ... (taint) | dates.js:48:31:48:90 | `Time i ... aint)}` |
869+
| dates.js:48:83:48:87 | taint | dates.js:48:42:48:88 | DateTim ... (taint) |
870+
| dates.js:49:42:49:87 | new Dat ... (taint) | dates.js:49:31:49:89 | `Time i ... aint)}` |
871+
| dates.js:49:42:49:87 | new Dat ... (taint) | dates.js:49:31:49:89 | `Time i ... aint)}` |
872+
| dates.js:49:82:49:86 | taint | dates.js:49:42:49:87 | new Dat ... (taint) |
873+
| dates.js:50:42:50:102 | DateTim ... (taint) | dates.js:50:31:50:104 | `Time i ... aint)}` |
874+
| dates.js:50:42:50:102 | DateTim ... (taint) | dates.js:50:31:50:104 | `Time i ... aint)}` |
875+
| dates.js:50:97:50:101 | taint | dates.js:50:42:50:102 | DateTim ... (taint) |
876+
| dates.js:54:9:54:69 | taint | dates.js:57:94:57:98 | taint |
877+
| dates.js:54:9:54:69 | taint | dates.js:59:80:59:84 | taint |
878+
| dates.js:54:9:54:69 | taint | dates.js:61:81:61:85 | taint |
879+
| dates.js:54:17:54:69 | decodeU ... ing(1)) | dates.js:54:9:54:69 | taint |
880+
| dates.js:54:36:54:55 | window.location.hash | dates.js:54:36:54:68 | window. ... ring(1) |
881+
| dates.js:54:36:54:55 | window.location.hash | dates.js:54:36:54:68 | window. ... ring(1) |
882+
| dates.js:54:36:54:68 | window. ... ring(1) | dates.js:54:17:54:69 | decodeU ... ing(1)) |
883+
| dates.js:57:42:57:99 | moment. ... (taint) | dates.js:57:31:57:101 | `Time i ... aint)}` |
884+
| dates.js:57:42:57:99 | moment. ... (taint) | dates.js:57:31:57:101 | `Time i ... aint)}` |
885+
| dates.js:57:94:57:98 | taint | dates.js:57:42:57:99 | moment. ... (taint) |
886+
| dates.js:59:42:59:85 | luxon.e ... (taint) | dates.js:59:31:59:87 | `Time i ... aint)}` |
887+
| dates.js:59:42:59:85 | luxon.e ... (taint) | dates.js:59:31:59:87 | `Time i ... aint)}` |
888+
| dates.js:59:80:59:84 | taint | dates.js:59:42:59:85 | luxon.e ... (taint) |
889+
| dates.js:61:42:61:86 | dayjs.s ... (taint) | dates.js:61:31:61:88 | `Time i ... aint)}` |
890+
| dates.js:61:42:61:86 | dayjs.s ... (taint) | dates.js:61:31:61:88 | `Time i ... aint)}` |
891+
| dates.js:61:81:61:85 | taint | dates.js:61:42:61:86 | dayjs.s ... (taint) |
777892
| event-handler-receiver.js:2:49:2:61 | location.href | event-handler-receiver.js:2:31:2:83 | '<h2><a ... ></h2>' |
778893
| event-handler-receiver.js:2:49:2:61 | location.href | event-handler-receiver.js:2:31:2:83 | '<h2><a ... ></h2>' |
779894
| event-handler-receiver.js:2:49:2:61 | location.href | event-handler-receiver.js:2:31:2:83 | '<h2><a ... ></h2>' |
@@ -1285,6 +1400,17 @@ edges
12851400
| dates.js:13:31:13:72 | `Time i ... time)}` | dates.js:9:36:9:55 | window.location.hash | dates.js:13:31:13:72 | `Time i ... time)}` | Cross-site scripting vulnerability due to $@. | dates.js:9:36:9:55 | window.location.hash | user-provided value |
12861401
| dates.js:16:31:16:69 | `Time i ... aint)}` | dates.js:9:36:9:55 | window.location.hash | dates.js:16:31:16:69 | `Time i ... aint)}` | Cross-site scripting vulnerability due to $@. | dates.js:9:36:9:55 | window.location.hash | user-provided value |
12871402
| dates.js:18:31:18:66 | `Time i ... aint)}` | dates.js:9:36:9:55 | window.location.hash | dates.js:18:31:18:66 | `Time i ... aint)}` | Cross-site scripting vulnerability due to $@. | dates.js:9:36:9:55 | window.location.hash | user-provided value |
1403+
| dates.js:21:31:21:68 | `Time i ... aint)}` | dates.js:9:36:9:55 | window.location.hash | dates.js:21:31:21:68 | `Time i ... aint)}` | Cross-site scripting vulnerability due to $@. | dates.js:9:36:9:55 | window.location.hash | user-provided value |
1404+
| dates.js:37:31:37:84 | `Time i ... aint)}` | dates.js:30:36:30:55 | window.location.hash | dates.js:37:31:37:84 | `Time i ... aint)}` | Cross-site scripting vulnerability due to $@. | dates.js:30:36:30:55 | window.location.hash | user-provided value |
1405+
| dates.js:38:31:38:84 | `Time i ... aint)}` | dates.js:30:36:30:55 | window.location.hash | dates.js:38:31:38:84 | `Time i ... aint)}` | Cross-site scripting vulnerability due to $@. | dates.js:30:36:30:55 | window.location.hash | user-provided value |
1406+
| dates.js:39:31:39:86 | `Time i ... aint)}` | dates.js:30:36:30:55 | window.location.hash | dates.js:39:31:39:86 | `Time i ... aint)}` | Cross-site scripting vulnerability due to $@. | dates.js:30:36:30:55 | window.location.hash | user-provided value |
1407+
| dates.js:40:31:40:84 | `Time i ... aint)}` | dates.js:30:36:30:55 | window.location.hash | dates.js:40:31:40:84 | `Time i ... aint)}` | Cross-site scripting vulnerability due to $@. | dates.js:30:36:30:55 | window.location.hash | user-provided value |
1408+
| dates.js:48:31:48:90 | `Time i ... aint)}` | dates.js:46:36:46:55 | window.location.hash | dates.js:48:31:48:90 | `Time i ... aint)}` | Cross-site scripting vulnerability due to $@. | dates.js:46:36:46:55 | window.location.hash | user-provided value |
1409+
| dates.js:49:31:49:89 | `Time i ... aint)}` | dates.js:46:36:46:55 | window.location.hash | dates.js:49:31:49:89 | `Time i ... aint)}` | Cross-site scripting vulnerability due to $@. | dates.js:46:36:46:55 | window.location.hash | user-provided value |
1410+
| dates.js:50:31:50:104 | `Time i ... aint)}` | dates.js:46:36:46:55 | window.location.hash | dates.js:50:31:50:104 | `Time i ... aint)}` | Cross-site scripting vulnerability due to $@. | dates.js:46:36:46:55 | window.location.hash | user-provided value |
1411+
| dates.js:57:31:57:101 | `Time i ... aint)}` | dates.js:54:36:54:55 | window.location.hash | dates.js:57:31:57:101 | `Time i ... aint)}` | Cross-site scripting vulnerability due to $@. | dates.js:54:36:54:55 | window.location.hash | user-provided value |
1412+
| dates.js:59:31:59:87 | `Time i ... aint)}` | dates.js:54:36:54:55 | window.location.hash | dates.js:59:31:59:87 | `Time i ... aint)}` | Cross-site scripting vulnerability due to $@. | dates.js:54:36:54:55 | window.location.hash | user-provided value |
1413+
| dates.js:61:31:61:88 | `Time i ... aint)}` | dates.js:54:36:54:55 | window.location.hash | dates.js:61:31:61:88 | `Time i ... aint)}` | Cross-site scripting vulnerability due to $@. | dates.js:54:36:54:55 | window.location.hash | user-provided value |
12881414
| event-handler-receiver.js:2:31:2:83 | '<h2><a ... ></h2>' | event-handler-receiver.js:2:49:2:61 | location.href | event-handler-receiver.js:2:31:2:83 | '<h2><a ... ></h2>' | Cross-site scripting vulnerability due to $@. | event-handler-receiver.js:2:49:2:61 | location.href | user-provided value |
12891415
| express.js:7:15:7:33 | req.param("wobble") | express.js:7:15:7:33 | req.param("wobble") | express.js:7:15:7:33 | req.param("wobble") | Cross-site scripting vulnerability due to $@. | express.js:7:15:7:33 | req.param("wobble") | user-provided value |
12901416
| jquery.js:7:5:7:34 | "<div i ... + "\\">" | jquery.js:2:17:2:40 | documen ... .search | jquery.js:7:5:7:34 | "<div i ... + "\\">" | Cross-site scripting vulnerability due to $@. | jquery.js:2:17:2:40 | documen ... .search | user-provided value |

0 commit comments

Comments
 (0)