@contrast/assess 1.31.0 → 1.32.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (154) hide show
  1. package/lib/crypto-analysis/install/crypto.test.js +146 -0
  2. package/lib/crypto-analysis/install/math.test.js +65 -0
  3. package/lib/dataflow/index.test.js +36 -0
  4. package/lib/dataflow/propagation/index.test.js +103 -0
  5. package/lib/dataflow/propagation/install/JSON/index.test.js +50 -0
  6. package/lib/dataflow/propagation/install/JSON/parse-fn.test.js +232 -0
  7. package/lib/dataflow/propagation/install/JSON/parse.test.js +968 -0
  8. package/lib/dataflow/propagation/install/JSON/stringify.test.js +265 -0
  9. package/lib/dataflow/propagation/install/array-prototype-join.test.js +106 -0
  10. package/lib/dataflow/propagation/install/buffer.test.js +109 -0
  11. package/lib/dataflow/propagation/install/contrast-methods/add.test.js +94 -0
  12. package/lib/dataflow/propagation/install/contrast-methods/index.test.js +49 -0
  13. package/lib/dataflow/propagation/install/contrast-methods/number.test.js +50 -0
  14. package/lib/dataflow/propagation/install/contrast-methods/string.test.js +148 -0
  15. package/lib/dataflow/propagation/install/contrast-methods/tag.test.js +145 -0
  16. package/lib/dataflow/propagation/install/decode-uri-component.test.js +78 -0
  17. package/lib/dataflow/propagation/install/ejs/escape-xml.test.js +69 -0
  18. package/lib/dataflow/propagation/install/ejs/template.test.js +62 -0
  19. package/lib/dataflow/propagation/install/encode-uri.test.js +83 -0
  20. package/lib/dataflow/propagation/install/escape-html.test.js +71 -0
  21. package/lib/dataflow/propagation/install/escape.test.js +73 -0
  22. package/lib/dataflow/propagation/install/handlebars-utils-escape-expression.test.js +71 -0
  23. package/lib/dataflow/propagation/install/isnumeric-0.test.js +58 -0
  24. package/lib/dataflow/propagation/install/joi/any.test.js +270 -0
  25. package/lib/dataflow/propagation/install/joi/array.test.js +912 -0
  26. package/lib/dataflow/propagation/install/joi/boolean.test.js +103 -0
  27. package/lib/dataflow/propagation/install/joi/expression.test.js +76 -0
  28. package/lib/dataflow/propagation/install/joi/index.test.js +39 -0
  29. package/lib/dataflow/propagation/install/joi/number.test.js +103 -0
  30. package/lib/dataflow/propagation/install/joi/object.test.js +119 -0
  31. package/lib/dataflow/propagation/install/joi/ref.test.js +607 -0
  32. package/lib/dataflow/propagation/install/joi/string-schema.test.js +513 -0
  33. package/lib/dataflow/propagation/install/mongoose/index.test.js +42 -0
  34. package/lib/dataflow/propagation/install/mongoose/schema-map.test.js +348 -0
  35. package/lib/dataflow/propagation/install/mongoose/schema-mixed.test.js +512 -0
  36. package/lib/dataflow/propagation/install/mongoose/schema-string.test.js +160 -0
  37. package/lib/dataflow/propagation/install/mustache-escape.test.js +62 -0
  38. package/lib/dataflow/propagation/install/mysql-connection-escape.test.js +74 -0
  39. package/lib/dataflow/propagation/install/parse-int.test.js +48 -0
  40. package/lib/dataflow/propagation/install/path/basename.test.js +143 -0
  41. package/lib/dataflow/propagation/install/path/dirname.test.js +167 -0
  42. package/lib/dataflow/propagation/install/path/extname.test.js +141 -0
  43. package/lib/dataflow/propagation/install/path/format.test.js +250 -0
  44. package/lib/dataflow/propagation/install/path/index.test.js +45 -0
  45. package/lib/dataflow/propagation/install/path/join-and-resolve.test.js +485 -0
  46. package/lib/dataflow/propagation/install/path/normalize.test.js +176 -0
  47. package/lib/dataflow/propagation/install/path/parse.test.js +238 -0
  48. package/lib/dataflow/propagation/install/path/relative.test.js +239 -0
  49. package/lib/dataflow/propagation/install/path/toNamespacedPath.test.js +158 -0
  50. package/lib/dataflow/propagation/install/pug/index.test.js +55 -0
  51. package/lib/dataflow/propagation/install/pug-runtime-escape.test.js +69 -0
  52. package/lib/dataflow/propagation/install/querystring/escape.test.js +63 -0
  53. package/lib/dataflow/propagation/install/querystring/index.test.js +40 -0
  54. package/lib/dataflow/propagation/install/querystring/parse.test.js +272 -0
  55. package/lib/dataflow/propagation/install/querystring/stringify.test.js +301 -0
  56. package/lib/dataflow/propagation/install/reg-exp-prototype-exec.test.js +281 -0
  57. package/lib/dataflow/propagation/install/send.test.js +63 -0
  58. package/lib/dataflow/propagation/install/sequelize/query-generator.test.js +73 -0
  59. package/lib/dataflow/propagation/install/sequelize/sql-string.test.js +130 -0
  60. package/lib/dataflow/propagation/install/sql-template-strings.test.js +100 -0
  61. package/lib/dataflow/propagation/install/string/concat.test.js +132 -0
  62. package/lib/dataflow/propagation/install/string/format-methods.test.js +61 -0
  63. package/lib/dataflow/propagation/install/string/html-methods.test.js +164 -0
  64. package/lib/dataflow/propagation/install/string/index.test.js +103 -0
  65. package/lib/dataflow/propagation/install/string/match-all.test.js +399 -0
  66. package/lib/dataflow/propagation/install/string/match.test.js +361 -0
  67. package/lib/dataflow/propagation/install/string/replace.test.js +588 -0
  68. package/lib/dataflow/propagation/install/string/slice.test.js +265 -0
  69. package/lib/dataflow/propagation/install/string/split.test.js +500 -0
  70. package/lib/dataflow/propagation/install/string/substring.test.js +238 -0
  71. package/lib/dataflow/propagation/install/string/trim.test.js +122 -0
  72. package/lib/dataflow/propagation/install/unescape.test.js +78 -0
  73. package/lib/dataflow/propagation/install/url/domain-parsers.test.js +63 -0
  74. package/lib/dataflow/propagation/install/url/parse.test.js +391 -0
  75. package/lib/dataflow/propagation/install/url/searchParams.test.js +538 -0
  76. package/lib/dataflow/propagation/install/url/url.test.js +466 -0
  77. package/lib/dataflow/propagation/install/util-format.test.js +336 -0
  78. package/lib/dataflow/propagation/install/validator/hooks.test.js +211 -0
  79. package/lib/dataflow/sinks/index.test.js +78 -0
  80. package/lib/dataflow/sinks/install/child-process.test.js +338 -0
  81. package/lib/dataflow/sinks/install/eval.test.js +95 -0
  82. package/lib/dataflow/sinks/install/express/index.test.js +33 -0
  83. package/lib/dataflow/sinks/install/express/reflected-xss.js +55 -57
  84. package/lib/dataflow/sinks/install/express/reflected-xss.test.js +109 -0
  85. package/lib/dataflow/sinks/install/express/unvalidated-redirect.test.js +144 -0
  86. package/lib/dataflow/sinks/install/fastify/index.test.js +32 -0
  87. package/lib/dataflow/sinks/install/fastify/unvalidated-redirect.test.js +130 -0
  88. package/lib/dataflow/sinks/install/fs.test.js +138 -0
  89. package/lib/dataflow/sinks/install/function.test.js +103 -0
  90. package/lib/dataflow/sinks/install/hapi/index.test.js +32 -0
  91. package/lib/dataflow/sinks/install/hapi/unvalidated-redirect.test.js +130 -0
  92. package/lib/dataflow/sinks/install/http/index.test.js +33 -0
  93. package/lib/dataflow/sinks/install/http/request.test.js +184 -0
  94. package/lib/dataflow/sinks/install/http/server-response.test.js +162 -0
  95. package/lib/dataflow/sinks/install/koa/index.test.js +32 -0
  96. package/lib/dataflow/sinks/install/koa/unvalidated-redirect.test.js +200 -0
  97. package/lib/dataflow/sinks/install/libxmljs.test.js +158 -0
  98. package/lib/dataflow/sinks/install/marsdb.test.js +166 -0
  99. package/lib/dataflow/sinks/install/mongodb.test.js +621 -0
  100. package/lib/dataflow/sinks/install/mssql.test.js +136 -0
  101. package/lib/dataflow/sinks/install/mysql.test.js +233 -0
  102. package/lib/dataflow/sinks/install/node-serialize.test.js +85 -0
  103. package/lib/dataflow/sinks/install/postgres.test.js +158 -0
  104. package/lib/dataflow/sinks/install/restify.test.js +142 -0
  105. package/lib/dataflow/sinks/install/sequelize.test.js +100 -0
  106. package/lib/dataflow/sinks/install/sqlite3.test.js +118 -0
  107. package/lib/dataflow/sinks/install/vm.test.js +326 -0
  108. package/lib/dataflow/sources/handler.test.js +463 -0
  109. package/lib/dataflow/sources/index.test.js +58 -0
  110. package/lib/dataflow/sources/install/body-parser1.test.js +248 -0
  111. package/lib/dataflow/sources/install/busboy.test.js +152 -0
  112. package/lib/dataflow/sources/install/cookie-parser1.test.js +143 -0
  113. package/lib/dataflow/sources/install/express/params.test.js +105 -0
  114. package/lib/dataflow/sources/install/express/parsedUrl.test.js +65 -0
  115. package/lib/dataflow/sources/install/fastify/fastify.test.js +210 -0
  116. package/lib/dataflow/sources/install/fastify/index.test.js +33 -0
  117. package/lib/dataflow/sources/install/formidable1.test.js +119 -0
  118. package/lib/dataflow/sources/install/hapi/hapi.test.js +172 -0
  119. package/lib/dataflow/sources/install/hapi/index.test.js +33 -0
  120. package/lib/dataflow/sources/install/http.test.js +155 -0
  121. package/lib/dataflow/sources/install/koa/index.test.js +40 -0
  122. package/lib/dataflow/sources/install/koa/koa-bodyparsers.test.js +161 -0
  123. package/lib/dataflow/sources/install/koa/koa-multer.test.js +197 -0
  124. package/lib/dataflow/sources/install/koa/koa-routers.test.js +146 -0
  125. package/lib/dataflow/sources/install/koa/koa2.test.js +145 -0
  126. package/lib/dataflow/sources/install/multer1.test.js +145 -0
  127. package/lib/dataflow/sources/install/qs6.test.js +131 -0
  128. package/lib/dataflow/sources/install/querystring.test.js +82 -0
  129. package/lib/dataflow/sources/install/restify/fieldedTextBodyParser.test.js +88 -0
  130. package/lib/dataflow/sources/install/restify/index.test.js +38 -0
  131. package/lib/dataflow/sources/install/restify/jsonBodyParser.test.js +144 -0
  132. package/lib/dataflow/sources/install/restify/router.test.js +83 -0
  133. package/lib/dataflow/tag-utils-complete.test.js +27 -0
  134. package/lib/dataflow/tag-utils.test.js +192 -0
  135. package/lib/dataflow/tracker.test.js +216 -0
  136. package/lib/dataflow/utils/is-safe-content-type.test.js +16 -0
  137. package/lib/dataflow/utils/is-vulnerable.test.js +115 -0
  138. package/lib/event-factory.test.js +321 -0
  139. package/lib/get-policy.test.js +194 -0
  140. package/lib/get-source-context.test.js +108 -0
  141. package/lib/index.test.js +41 -0
  142. package/lib/make-source-context.test.js +50 -0
  143. package/lib/response-scanning/handlers/index.test.js +425 -0
  144. package/lib/response-scanning/handlers/utils.test.js +391 -0
  145. package/lib/response-scanning/index.test.js +41 -0
  146. package/lib/response-scanning/install/http.test.js +175 -0
  147. package/lib/rule-scopes.test.js +27 -0
  148. package/lib/session-configuration/handlers.test.js +84 -0
  149. package/lib/session-configuration/index.test.js +36 -0
  150. package/lib/session-configuration/install/express-session.test.js +220 -0
  151. package/lib/session-configuration/install/fastify-cookie.test.js +65 -0
  152. package/lib/session-configuration/install/hapi.test.js +269 -0
  153. package/lib/session-configuration/install/koa.test.js +92 -0
  154. package/package.json +2 -2
@@ -0,0 +1,538 @@
1
+ 'use strict';
2
+
3
+ const url = require('url');
4
+ const { expect } = require('chai');
5
+ const sinon = require('sinon');
6
+ const { initAssessFixture } = require('@contrast/test/fixtures');
7
+
8
+ describe('assess dataflow propagation url.URLSearchParams', function () {
9
+ let core, trackString, simulateRequestScope, tracker;
10
+
11
+ beforeEach(function () {
12
+ ({
13
+ core,
14
+ simulateRequestScope,
15
+ trackString
16
+ } = initAssessFixture());
17
+
18
+ tracker = core.assess.dataflow.tracker;
19
+ core.assess.dataflow.propagation.stringInstrumentation.split.install();
20
+ core.assess.dataflow.propagation.stringInstrumentation.concat.install();
21
+ core.assess.dataflow.propagation.stringInstrumentation.substring.install();
22
+ core.assess.dataflow.propagation.urlInstrumentation.searchParams.install();
23
+ core.depHooks.resolve.yield(url);
24
+ });
25
+
26
+ afterEach(function () {
27
+ sinon.resetHistory();
28
+ core.assess.dataflow.propagation.stringInstrumentation.split.uninstall();
29
+ core.assess.dataflow.propagation.stringInstrumentation.concat.uninstall();
30
+ core.assess.dataflow.propagation.stringInstrumentation.substring.uninstall();
31
+
32
+ });
33
+
34
+ it('will not propagate if nothing in the search params is tracked', function () {
35
+ simulateRequestScope(function () {
36
+ const result = new url.URLSearchParams('?query=foo');
37
+ const input = result.get('query');
38
+ expect(input).to.be.equal('foo');
39
+ expect(tracker.getData(input)).to.be.null;
40
+ });
41
+ });
42
+
43
+ it('will not propagate if there is no assess context', function () {
44
+ simulateRequestScope(function () {
45
+ const value = trackString('foo');
46
+ const result = new url.URLSearchParams('?query='.concat(value));
47
+ const input = result.get('query');
48
+ expect(input).to.be.equal('foo');
49
+ expect(tracker.getData(input)).to.be.null;
50
+ }, {});
51
+ });
52
+
53
+ it('will not propagate if instrumentation is locked', function () {
54
+ simulateRequestScope(function () {
55
+ core.scopes.instrumentation.run({ lock: true }, function () {
56
+ const value = trackString('foo');
57
+ const result = new url.URLSearchParams('?query='.concat(value));
58
+ const input = result.get('query');
59
+ expect(input).to.be.equal('foo');
60
+ expect(tracker.getData(input)).to.be.null;
61
+ });
62
+ });
63
+ });
64
+
65
+ it('does not break methods', function () {
66
+ simulateRequestScope(function () {
67
+ const result = new url.URLSearchParams('?query=foo');
68
+ const input = result.get('query');
69
+ expect(input).to.be.equal('foo');
70
+
71
+ result.set('query2', 'bar');
72
+ expect(result.get('query2')).to.be.equal('bar');
73
+
74
+ result.append('query3', 'fizz');
75
+ expect(result.get('query3')).to.be.equal('fizz');
76
+
77
+ result.delete('query2');
78
+ result.delete('query3');
79
+ expect(result.get('query2')).to.be.null;
80
+ expect(result.get('query3')).to.be.null;
81
+
82
+ for (const entry of result.entries()) {
83
+ expect(entry).to.be.deep.equal(['query', 'foo']);
84
+ }
85
+
86
+ result.forEach((val, key) => {
87
+ expect(val).to.be.equal('foo');
88
+ expect(key).to.be.equal('query');
89
+ });
90
+
91
+ result.append('query', 'bar');
92
+ expect(result.getAll('query')).to.be.deep.equal(['foo', 'bar']);
93
+
94
+ expect(result.has('query')).to.be.true;
95
+ expect(result.has('query', 'bar')).to.be.true;
96
+
97
+ for (const key of result.keys()) {
98
+ expect(key).to.be.equal('query');
99
+ }
100
+
101
+ result.append('input', 'fizz');
102
+ result.sort();
103
+ expect(result.toString()).to.be.equal('input=fizz&query=foo&query=bar');
104
+ });
105
+ });
106
+
107
+ it('keeps track of vulnerable params set', function () {
108
+ simulateRequestScope(function () {
109
+ const value = trackString('foo');
110
+ const result = new url.URLSearchParams();
111
+
112
+ result.set('query', value);
113
+ const input = result.get('query');
114
+ expect(input).to.be.equal('foo');
115
+ expect(tracker.getData(input).tags).to.be.deep.equal({
116
+ UNTRUSTED: [0, 2]
117
+ });
118
+ });
119
+ });
120
+
121
+ it('keeps track of vulnerable params appended', function () {
122
+ simulateRequestScope(function () {
123
+ const value = trackString('foo');
124
+ const result = new url.URLSearchParams();
125
+
126
+ result.append('query', value);
127
+ const input = result.get('query');
128
+ expect(input).to.be.equal('foo');
129
+ expect(tracker.getData(input).tags).to.be.deep.equal({
130
+ UNTRUSTED: [0, 2]
131
+ });
132
+ });
133
+ });
134
+
135
+ describe('params object', function () {
136
+
137
+ it('propagates through get', function () {
138
+ simulateRequestScope(function () {
139
+ const value = trackString('foo');
140
+ const result = new url.URLSearchParams({ query: value });
141
+
142
+ const input = result.get('query');
143
+ expect(input).to.be.equal('foo');
144
+ expect(tracker.getData(input).tags).to.deep.equal({
145
+ UNTRUSTED: [0, 2]
146
+ });
147
+ });
148
+ });
149
+
150
+ it('propagates through toString()', function () {
151
+ simulateRequestScope(function () {
152
+ const value = trackString('foo');
153
+ const result = new url.URLSearchParams({ query: value });
154
+
155
+ const input = result.toString();
156
+ expect(input).to.be.equal('query=foo');
157
+ expect(tracker.getData(input).tags).to.deep.equal({
158
+ UNTRUSTED: [6, 8]
159
+ });
160
+ });
161
+ });
162
+
163
+ it('propagates duplicates through toString()', function() {
164
+ simulateRequestScope(function() {
165
+ const value = trackString('foo');
166
+ const result = new url.URLSearchParams({ query: value });
167
+ result.append('query', value);
168
+
169
+ const input = result.toString();
170
+ expect(input).to.be.equal('query=foo&query=foo');
171
+ expect(tracker.getData(input).tags).to.deep.equal({
172
+ UNTRUSTED: [6, 8, 16, 18]
173
+ });
174
+ });
175
+ });
176
+
177
+ it('propagates spaces to pluses through toString()', function() {
178
+ simulateRequestScope(function() {
179
+ const value = trackString('foo bar');
180
+ const result = new url.URLSearchParams({ query: value });
181
+
182
+ const input = result.toString();
183
+ expect(input).to.be.equal('query=foo+bar');
184
+ expect(tracker.getData(input).tags).to.deep.equal({
185
+ UNTRUSTED: [6, 12]
186
+ });
187
+ });
188
+ });
189
+
190
+ it('propagates through entries', function () {
191
+ simulateRequestScope(function () {
192
+ const value = trackString('foo');
193
+ const result = new url.URLSearchParams({ query: value });
194
+
195
+ for (const entry of result.entries()) {
196
+ expect(entry).to.be.deep.equal(['query', 'foo']);
197
+ expect(tracker.getData(entry[1]).tags).to.be.deep.equal({
198
+ UNTRUSTED: [0, 2]
199
+ });
200
+ }
201
+ });
202
+ });
203
+
204
+ it('propagates through forEach', function () {
205
+ simulateRequestScope(function () {
206
+ const value = trackString('foo');
207
+ const result = new url.URLSearchParams({ query: value });
208
+
209
+ result.forEach((val, key) => {
210
+ expect(key).to.be.equal('query');
211
+ expect(val).to.be.equal('foo');
212
+ expect(tracker.getData(val).tags).to.be.deep.equal({
213
+ UNTRUSTED: [0, 2]
214
+ });
215
+ });
216
+ });
217
+ });
218
+
219
+ // eslint-disable-next-line
220
+ it.skip('keeps track of vulnerable keys', function () {
221
+ simulateRequestScope(function () {
222
+ const obj = {};
223
+ const value = trackString('query');
224
+ // TO DO: NODE-3067: Tracking lost on object keys
225
+ obj[value] = 'foo';
226
+ const result = new url.URLSearchParams(obj);
227
+
228
+ for (const [key, val] of result.entries()) {
229
+ expect(key).to.be.equal('query');
230
+ expect(val).to.be.equal('foo');
231
+ expect(tracker.getData(key).tags).to.be.deep.equal({
232
+ UNTRUSTED: [0, 4]
233
+ });
234
+ expect(tracker.getData(val)).to.be.null;
235
+ }
236
+
237
+ result.forEach((val, key) => {
238
+ expect(key).to.be.equal('query');
239
+ expect(val).to.be.equal('foo');
240
+ expect(tracker.getData(key).tags).to.be.deep.equal({
241
+ UNTRUSTED: [0, 4]
242
+ });
243
+ expect(tracker.getData(val)).to.be.null;
244
+ });
245
+
246
+ const input = result.toString();
247
+ expect(input).to.be.equal('query=foo');
248
+ expect(tracker.getData(input).tags).to.be.deep.equal({
249
+ UNTRUSTED: [0, 4]
250
+ });
251
+ });
252
+ });
253
+
254
+ it('keeps track of multiple vulnerable parameters', function () {
255
+ simulateRequestScope(function () {
256
+ const foo = trackString('foo');
257
+ const bar = trackString('bar');
258
+ const result = new url.URLSearchParams({ foo, bar });
259
+
260
+ const fizz = trackString('fizz');
261
+ const buzz = trackString('buzz');
262
+
263
+ result.set('fizz', fizz);
264
+ result.append('buzz', buzz);
265
+
266
+ const params1 = result.get('foo');
267
+ expect(params1).to.be.equal('foo');
268
+ expect(tracker.getData(params1).tags).to.be.deep.equal({
269
+ UNTRUSTED: [0, 2]
270
+ });
271
+
272
+ const params2 = result.get('bar');
273
+ expect(params2).to.be.equal('bar');
274
+ expect(tracker.getData(params2).tags).to.be.deep.equal({
275
+ UNTRUSTED: [0, 2]
276
+ });
277
+
278
+ const params3 = result.get('fizz');
279
+ expect(params3).to.be.equal('fizz');
280
+ expect(tracker.getData(params3).tags).to.be.deep.equal({
281
+ UNTRUSTED: [0, 3]
282
+ });
283
+
284
+ const params4 = result.get('buzz');
285
+ expect(params4).to.be.equal('buzz');
286
+ expect(tracker.getData(params4).tags).to.be.deep.equal({
287
+ UNTRUSTED: [0, 3]
288
+ });
289
+
290
+ const str = result.toString();
291
+ // 0 1 2 3
292
+ // 012 456 890 234 6789 1234 6789 1234
293
+ expect(str).to.be.equal('foo=foo&bar=bar&fizz=fizz&buzz=buzz');
294
+ expect(tracker.getData(str).tags).to.be.deep.equal({
295
+ UNTRUSTED: [4, 6, 12, 14, 21, 24, 31, 34]
296
+ });
297
+
298
+ result.sort();
299
+ const str2 = result.toString();
300
+ expect(str2).to.be.equal('bar=bar&buzz=buzz&fizz=fizz&foo=foo');
301
+ expect(tracker.getData(str2).tags).to.be.deep.equal({
302
+ UNTRUSTED: [4, 6, 13, 16, 23, 26, 32, 34]
303
+ });
304
+ });
305
+ });
306
+ });
307
+
308
+ describe('params string', function () {
309
+ it('propagates through get', function () {
310
+ simulateRequestScope(function () {
311
+ const value = trackString('?query=foo', { tags: { UNTRUSTED: [7, 9] } });
312
+ const result = new url.URLSearchParams(value);
313
+
314
+ const input = result.get('query');
315
+ expect(input).to.be.equal('foo');
316
+ expect(tracker.getData(input).tags).to.be.deep.equal({
317
+ UNTRUSTED: [0, 2]
318
+ });
319
+ });
320
+ });
321
+
322
+ it('propagates through toString', function () {
323
+ simulateRequestScope(function () {
324
+ const value = trackString('?query=foo', { tags: { UNTRUSTED: [7, 9] } });
325
+ const result = new url.URLSearchParams(value);
326
+
327
+ const input = result.toString();
328
+ expect(input).to.be.equal('query=foo');
329
+ expect(tracker.getData(input).tags).to.be.deep.equal({
330
+ UNTRUSTED: [6, 8]
331
+ });
332
+ });
333
+ });
334
+
335
+ it('propagates through entries', function () {
336
+ simulateRequestScope(function () {
337
+ const value = trackString('?query=foo', { tags: { UNTRUSTED: [7, 9] } });
338
+ const result = new url.URLSearchParams(value);
339
+
340
+ for (const [key, val] of result.entries()) {
341
+ expect(key).to.be.equal('query');
342
+ expect(val).to.be.equal('foo');
343
+ expect(tracker.getData(val).tags).to.be.deep.equal({
344
+ UNTRUSTED: [0, 2]
345
+ });
346
+ }
347
+ });
348
+ });
349
+
350
+ it('propagates through forEach', function () {
351
+ simulateRequestScope(function () {
352
+ const value = trackString('?query=foo', { tags: { UNTRUSTED: [7, 9] } });
353
+ const result = new url.URLSearchParams(value);
354
+
355
+ result.forEach((val, key) => {
356
+ expect(key).to.be.equal('query');
357
+ expect(val).to.be.equal('foo');
358
+ expect(tracker.getData(val).tags).to.be.deep.equal({
359
+ UNTRUSTED: [0, 2]
360
+ });
361
+ });
362
+ });
363
+ });
364
+
365
+ it('keeps track of vulnerable keys', function () {
366
+ simulateRequestScope(function () {
367
+ const value = trackString('?query=foo', { tags: { UNTRUSTED: [1, 5] } });
368
+ const result = new url.URLSearchParams(value);
369
+
370
+ for (const [key, val] of result.entries()) {
371
+ expect(key).to.be.equal('query');
372
+ expect(val).to.be.equal('foo');
373
+ expect(tracker.getData(key).tags).to.be.deep.equal({
374
+ UNTRUSTED: [0, 4]
375
+ });
376
+ expect(tracker.getData(val)).to.be.null;
377
+ }
378
+
379
+ result.forEach((val, key) => {
380
+ expect(key).to.be.equal('query');
381
+ expect(val).to.be.equal('foo');
382
+ expect(tracker.getData(key).tags).to.be.deep.equal({
383
+ UNTRUSTED: [0, 4]
384
+ });
385
+ expect(tracker.getData(val)).to.be.null;
386
+ });
387
+
388
+ const input = result.toString();
389
+ expect(input).to.be.equal('query=foo');
390
+ expect(tracker.getData(input).tags).to.be.deep.equal({
391
+ UNTRUSTED: [0, 4]
392
+ });
393
+ });
394
+ });
395
+
396
+ it('keeps track of multiple vulnerable parameters', function () {
397
+ simulateRequestScope(function () {
398
+ const value = trackString('?foo=foo&bar=bar', { tags: { UNTRUSTED: [5, 7, 13, 15] } });
399
+ const result = new url.URLSearchParams(value);
400
+
401
+ const fizz = trackString('fizz');
402
+ const buzz = trackString('buzz');
403
+
404
+ result.set('fizz', fizz);
405
+ result.append('buzz', buzz);
406
+
407
+ const params1 = result.get('foo');
408
+ expect(params1).to.be.equal('foo');
409
+ expect(tracker.getData(params1).tags).to.be.deep.equal({
410
+ UNTRUSTED: [0, 2]
411
+ });
412
+
413
+ const params2 = result.get('bar');
414
+ expect(params2).to.be.equal('bar');
415
+ expect(tracker.getData(params2).tags).to.be.deep.equal({
416
+ UNTRUSTED: [0, 2]
417
+ });
418
+
419
+ const params3 = result.get('fizz');
420
+ expect(params3).to.be.equal('fizz');
421
+ expect(tracker.getData(params3).tags).to.be.deep.equal({
422
+ UNTRUSTED: [0, 3]
423
+ });
424
+
425
+ const params4 = result.get('buzz');
426
+ expect(params4).to.be.equal('buzz');
427
+ expect(tracker.getData(params4).tags).to.be.deep.equal({
428
+ UNTRUSTED: [0, 3]
429
+ });
430
+
431
+ const str = result.toString();
432
+ expect(str).to.be.equal('foo=foo&bar=bar&fizz=fizz&buzz=buzz');
433
+ expect(tracker.getData(str).tags).to.be.deep.equal({
434
+ UNTRUSTED: [4, 6, 12, 14, 21, 24, 31, 34]
435
+ });
436
+
437
+ result.sort();
438
+ const str2 = result.toString();
439
+ expect(str2).to.be.equal('bar=bar&buzz=buzz&fizz=fizz&foo=foo');
440
+ expect(tracker.getData(str2).tags).to.be.deep.equal({
441
+ UNTRUSTED: [4, 6, 13, 16, 23, 26, 32, 34]
442
+ });
443
+ });
444
+ });
445
+ });
446
+
447
+ describe('params iterable', function () {
448
+ it('keeps tracking a matrix input', function () {
449
+ simulateRequestScope(function () {
450
+ const foo = trackString('foo');
451
+ const bar = trackString('bar');
452
+ const result = new url.URLSearchParams([
453
+ ['param1', foo],
454
+ ['param2', bar]
455
+ ]);
456
+
457
+ const str = result.toString();
458
+ expect(str).to.be.equal('param1=foo&param2=bar');
459
+ expect(tracker.getData(str).tags).to.be.deep.equal({
460
+ UNTRUSTED: [7, 9, 18, 20]
461
+ });
462
+
463
+ for (const [, val] of result.entries()) {
464
+ expect(tracker.getData(val).tags).to.be.deep.equal({
465
+ UNTRUSTED: [0, 2]
466
+ });
467
+ }
468
+
469
+ result.forEach((val, key) => {
470
+ expect(tracker.getData(val).tags).to.be.deep.equal({
471
+ UNTRUSTED: [0, 2]
472
+ });
473
+ });
474
+ });
475
+ });
476
+
477
+ it('keeps tracking a Map input', function () {
478
+ simulateRequestScope(function () {
479
+ const foo = trackString('foo');
480
+ const bar = trackString('bar');
481
+ const map = new Map();
482
+ map.set('param1', foo);
483
+ map.set('param2', bar);
484
+
485
+ const result = new url.URLSearchParams(map);
486
+
487
+ const str = result.toString();
488
+ expect(str).to.be.equal('param1=foo&param2=bar');
489
+ expect(tracker.getData(str).tags).to.be.deep.equal({
490
+ UNTRUSTED: [7, 9, 18, 20]
491
+ });
492
+
493
+ for (const [, val] of result.entries()) {
494
+ expect(tracker.getData(val).tags).to.be.deep.equal({
495
+ UNTRUSTED: [0, 2]
496
+ });
497
+ }
498
+
499
+ result.forEach((val, key) => {
500
+ expect(tracker.getData(val).tags).to.be.deep.equal({
501
+ UNTRUSTED: [0, 2]
502
+ });
503
+ });
504
+ });
505
+ });
506
+
507
+ it('keeps tracking a generator function input', function () {
508
+ simulateRequestScope(function () {
509
+ const foo = trackString('foo');
510
+ const bar = trackString('bar');
511
+
512
+ function* getQueryPairs() {
513
+ yield ['param1', foo];
514
+ yield ['param2', bar];
515
+ }
516
+ const result = new url.URLSearchParams(getQueryPairs());
517
+
518
+ const str = result.toString();
519
+ expect(str).to.be.equal('param1=foo&param2=bar');
520
+ expect(tracker.getData(str).tags).to.be.deep.equal({
521
+ UNTRUSTED: [7, 9, 18, 20]
522
+ });
523
+
524
+ for (const [, val] of result.entries()) {
525
+ expect(tracker.getData(val).tags).to.be.deep.equal({
526
+ UNTRUSTED: [0, 2]
527
+ });
528
+ }
529
+
530
+ result.forEach((val, key) => {
531
+ expect(tracker.getData(val).tags).to.be.deep.equal({
532
+ UNTRUSTED: [0, 2]
533
+ });
534
+ });
535
+ });
536
+ });
537
+ });
538
+ });