Skip to content

Commit 227f61b

Browse files
committed
add model for the luxon library
1 parent cdf3cdc commit 227f61b

File tree

5 files changed

+122
-2
lines changed

5 files changed

+122
-2
lines changed
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
lgtm,codescanning
22
* Improved support for date parsing libraries, resulting in more results in security queries.
33
Affected packages are
4-
[dayjs](https://npmjs.com/package/dayjs)
4+
[dayjs](https://npmjs.com/package/dayjs),
5+
[luxon](https://npmjs.com/package/luxon)
56

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

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,45 @@ private module DateIO {
7575
}
7676
}
7777

78+
/**
79+
* Provides classes and predicates modelling the `luxon` library.
80+
*/
81+
private module Luxon {
82+
/**
83+
* Gets a reference to a `DateTime` object from the `luxon` library.
84+
*/
85+
private API::Node luxonDateTime() {
86+
exists(API::Node constructor | constructor = API::moduleImport("luxon").getMember("DateTime") |
87+
result = constructor.getInstance()
88+
or
89+
result =
90+
constructor
91+
.getMember([
92+
"fromJSDate", "fromJSDate", "fromISO", "now", "fromMillis", "fromHTTP",
93+
"fromObject", "fromRFC2822", "fromSeconds", "fromSQL", "fromFormat", "fromString",
94+
"invalid", "local", "utc"
95+
])
96+
.getReturn()
97+
or
98+
// fluent API that return immutable objects
99+
result = luxonDateTime().getAMember()
100+
or
101+
result = luxonDateTime().getReturn()
102+
)
103+
}
104+
105+
/**
106+
* A step of the form: `f -> luxonDateTime.toFormat(f)`.
107+
*/
108+
private class ToFormatStep extends TaintTracking::SharedTaintStep {
109+
override predicate stringManipulationStep(DataFlow::Node pred, DataFlow::Node succ) {
110+
exists(API::CallNode call | call = luxonDateTime().getMember("toFormat").getACall() |
111+
pred = call.getArgument(0) and succ = call
112+
)
113+
}
114+
}
115+
}
116+
78117
private module Moment {
79118
/** Gets a reference to a `moment` object. */
80119
private API::Node moment() {

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

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,23 @@ nodes
151151
| dates.js:40:31:40:84 | `Time i ... aint)}` |
152152
| dates.js:40:42:40:82 | dayjs.f ... taint) |
153153
| 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 |
154171
| event-handler-receiver.js:2:31:2:83 | '<h2><a ... ></h2>' |
155172
| event-handler-receiver.js:2:31:2:83 | '<h2><a ... ></h2>' |
156173
| event-handler-receiver.js:2:49:2:61 | location.href |
@@ -823,6 +840,22 @@ edges
823840
| dates.js:40:42:40:82 | dayjs.f ... taint) | dates.js:40:31:40:84 | `Time i ... aint)}` |
824841
| dates.js:40:42:40:82 | dayjs.f ... taint) | dates.js:40:31:40:84 | `Time i ... aint)}` |
825842
| dates.js:40:77:40:81 | taint | dates.js:40:42:40:82 | dayjs.f ... taint) |
843+
| dates.js:46:9:46:69 | taint | dates.js:48:83:48:87 | taint |
844+
| dates.js:46:9:46:69 | taint | dates.js:49:82:49:86 | taint |
845+
| dates.js:46:9:46:69 | taint | dates.js:50:97:50:101 | taint |
846+
| dates.js:46:17:46:69 | decodeU ... ing(1)) | dates.js:46:9:46:69 | taint |
847+
| dates.js:46:36:46:55 | window.location.hash | dates.js:46:36:46:68 | window. ... ring(1) |
848+
| dates.js:46:36:46:55 | window.location.hash | dates.js:46:36:46:68 | window. ... ring(1) |
849+
| dates.js:46:36:46:68 | window. ... ring(1) | dates.js:46:17:46:69 | decodeU ... ing(1)) |
850+
| dates.js:48:42:48:88 | DateTim ... (taint) | dates.js:48:31:48:90 | `Time i ... aint)}` |
851+
| dates.js:48:42:48:88 | DateTim ... (taint) | dates.js:48:31:48:90 | `Time i ... aint)}` |
852+
| dates.js:48:83:48:87 | taint | dates.js:48:42:48:88 | DateTim ... (taint) |
853+
| dates.js:49:42:49:87 | new Dat ... (taint) | dates.js:49:31:49:89 | `Time i ... aint)}` |
854+
| dates.js:49:42:49:87 | new Dat ... (taint) | dates.js:49:31:49:89 | `Time i ... aint)}` |
855+
| dates.js:49:82:49:86 | taint | dates.js:49:42:49:87 | new Dat ... (taint) |
856+
| dates.js:50:42:50:102 | DateTim ... (taint) | dates.js:50:31:50:104 | `Time i ... aint)}` |
857+
| dates.js:50:42:50:102 | DateTim ... (taint) | dates.js:50:31:50:104 | `Time i ... aint)}` |
858+
| dates.js:50:97:50:101 | taint | dates.js:50:42:50:102 | DateTim ... (taint) |
826859
| event-handler-receiver.js:2:49:2:61 | location.href | event-handler-receiver.js:2:31:2:83 | '<h2><a ... ></h2>' |
827860
| event-handler-receiver.js:2:49:2:61 | location.href | event-handler-receiver.js:2:31:2:83 | '<h2><a ... ></h2>' |
828861
| event-handler-receiver.js:2:49:2:61 | location.href | event-handler-receiver.js:2:31:2:83 | '<h2><a ... ></h2>' |
@@ -1339,6 +1372,9 @@ edges
13391372
| 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 |
13401373
| 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 |
13411374
| 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 |
1375+
| 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 |
1376+
| 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 |
1377+
| 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 |
13421378
| 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 |
13431379
| 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 |
13441380
| 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 |

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

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,23 @@ nodes
151151
| dates.js:40:31:40:84 | `Time i ... aint)}` |
152152
| dates.js:40:42:40:82 | dayjs.f ... taint) |
153153
| 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 |
154171
| event-handler-receiver.js:2:31:2:83 | '<h2><a ... ></h2>' |
155172
| event-handler-receiver.js:2:31:2:83 | '<h2><a ... ></h2>' |
156173
| event-handler-receiver.js:2:49:2:61 | location.href |
@@ -841,6 +858,22 @@ edges
841858
| dates.js:40:42:40:82 | dayjs.f ... taint) | dates.js:40:31:40:84 | `Time i ... aint)}` |
842859
| dates.js:40:42:40:82 | dayjs.f ... taint) | dates.js:40:31:40:84 | `Time i ... aint)}` |
843860
| dates.js:40:77:40:81 | taint | dates.js:40:42:40:82 | dayjs.f ... taint) |
861+
| dates.js:46:9:46:69 | taint | dates.js:48:83:48:87 | taint |
862+
| dates.js:46:9:46:69 | taint | dates.js:49:82:49:86 | taint |
863+
| dates.js:46:9:46:69 | taint | dates.js:50:97:50:101 | taint |
864+
| dates.js:46:17:46:69 | decodeU ... ing(1)) | dates.js:46:9:46:69 | taint |
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:55 | window.location.hash | dates.js:46:36:46:68 | window. ... ring(1) |
867+
| dates.js:46:36:46:68 | window. ... ring(1) | dates.js:46:17:46:69 | decodeU ... ing(1)) |
868+
| dates.js:48:42:48:88 | DateTim ... (taint) | dates.js:48:31:48:90 | `Time i ... aint)}` |
869+
| dates.js:48:42:48:88 | DateTim ... (taint) | dates.js:48:31:48:90 | `Time i ... aint)}` |
870+
| dates.js:48:83:48:87 | taint | dates.js:48:42:48:88 | DateTim ... (taint) |
871+
| dates.js:49:42:49:87 | new Dat ... (taint) | dates.js:49:31:49:89 | `Time i ... aint)}` |
872+
| dates.js:49:42:49:87 | new Dat ... (taint) | dates.js:49:31:49:89 | `Time i ... aint)}` |
873+
| dates.js:49:82:49:86 | taint | dates.js:49:42:49:87 | new Dat ... (taint) |
874+
| dates.js:50:42:50:102 | DateTim ... (taint) | dates.js:50:31:50:104 | `Time i ... aint)}` |
875+
| dates.js:50:42:50:102 | DateTim ... (taint) | dates.js:50:31:50:104 | `Time i ... aint)}` |
876+
| dates.js:50:97:50:101 | taint | dates.js:50:42:50:102 | DateTim ... (taint) |
844877
| event-handler-receiver.js:2:49:2:61 | location.href | event-handler-receiver.js:2:31:2:83 | '<h2><a ... ></h2>' |
845878
| event-handler-receiver.js:2:49:2:61 | location.href | event-handler-receiver.js:2:31:2:83 | '<h2><a ... ></h2>' |
846879
| event-handler-receiver.js:2:49:2:61 | location.href | event-handler-receiver.js:2:31:2:83 | '<h2><a ... ></h2>' |

javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/dates.js

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,15 @@ function dateio() {
3838
document.body.innerHTML = `Time is ${luxon.formatByString(luxon.date(), taint)}`; // NOT OK
3939
document.body.innerHTML = `Time is ${moment.formatByString(moment.date(), taint)}`; // NOT OK
4040
document.body.innerHTML = `Time is ${dayjs.formatByString(dayjs.date(), taint)}`; // NOT OK
41-
}
41+
}
42+
43+
import { DateTime } from "luxon";
44+
45+
function luxon() {
46+
let taint = decodeURIComponent(window.location.hash.substring(1));
47+
48+
document.body.innerHTML = `Time is ${DateTime.now().plus({years: 1}).toFormat(taint)}`; // NOT OK
49+
document.body.innerHTML = `Time is ${new DateTime().setLocale('fr').toFormat(taint)}`; // NOT OK
50+
document.body.innerHTML = `Time is ${DateTime.fromISO("2020-01-01").startOf('day').toFormat(taint)}`; // NOT OK
51+
}
52+

0 commit comments

Comments
 (0)