From e8b233f086d6da58008723f467e332201ffa3f42 Mon Sep 17 00:00:00 2001 From: Napalys Date: Mon, 17 Mar 2025 12:48:41 +0100 Subject: [PATCH 01/23] Added test cases `underscore.string` string to string. --- .../TripleDot/underscore.string.js | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 javascript/ql/test/library-tests/TripleDot/underscore.string.js diff --git a/javascript/ql/test/library-tests/TripleDot/underscore.string.js b/javascript/ql/test/library-tests/TripleDot/underscore.string.js new file mode 100644 index 000000000000..618a6e68261e --- /dev/null +++ b/javascript/ql/test/library-tests/TripleDot/underscore.string.js @@ -0,0 +1,35 @@ +var s = require("underscore.string"); + +function strToStr() { + sink(s.slugify(source("s1"))); // $ MISSING: hasTaintFlow=s1 + sink(s.capitalize(source("s2"))); // $ MISSING: hasTaintFlow=s2 + sink(s.decapitalize(source("s3"))); // $ MISSING: hasTaintFlow=s3 + sink(s.clean(source("s4"))); // $ MISSING: hasTaintFlow=s4 + sink(s.cleanDiacritics(source("s5"))); // $ MISSING: hasTaintFlow=s5 + sink(s.swapCase(source("s6"))); // $ MISSING: hasTaintFlow=s6 + sink(s.escapeHTML(source("s7"))); // $ MISSING: hasTaintFlow=s7 + sink(s.unescapeHTML(source("s8"))); // $ MISSING: hasTaintFlow=s8 + sink(s.wrap(source("s9"), {})); // $ MISSING: hasTaintFlow=s9 + sink(s.dedent(source("s10"), " ")); // $ MISSING: hasTaintFlow=s10 + sink(s.reverse(source("s11"))); // $ MISSING: hasTaintFlow=s11 + sink(s.pred(source("s12"))); // $ MISSING: hasTaintFlow=s12 + sink(s.succ(source("s13"))); // $ MISSING: hasTaintFlow=s13 + sink(s.titleize(source("s14"))); // $ MISSING: hasTaintFlow=s14 + sink(s.camelize(source("s15"))); // $ MISSING: hasTaintFlow=s15 + sink(s.classify(source("s16"))); // $ MISSING: hasTaintFlow=s16 + sink(s.underscored(source("s17"))); // $ MISSING: hasTaintFlow=s17 + sink(s.dasherize(source("s18"))); // $ MISSING: hasTaintFlow=s18 + sink(s.humanize(source("s19"))); // $ MISSING: hasTaintFlow=s19 + sink(s.trim(source("s20"),"charsToStrim")); // $ MISSING: hasTaintFlow=s20 + sink(s.ltrim(source("s21"),"charsToStrim")); // $ MISSING: hasTaintFlow=s21 + sink(s.rtrim(source("s22"),"charsToStrim")); // $ MISSING: hasTaintFlow=s22 + sink(s.truncate(source("s23"), 10)); // $ MISSING: hasTaintFlow=s23 + sink(s.sprintf(source("s24"), 1.17)); // $ MISSING: hasTaintFlow=s24 + sink(s.strRight(source("s25"), "pattern")); // $ MISSING: hasTaintFlow=s25 + sink(s.strRightBack(source("s26"), "pattern")); // $ MISSING: hasTaintFlow=s26 + sink(s.strLeft(source("s27"), "pattern")); // $ MISSING: hasTaintFlow=s27 + sink(s.strLeftBack(source("s28"), "pattern")); // $ MISSING: hasTaintFlow=s28 + sink(s.stripTags(source("s29"))); // $ MISSING: hasTaintFlow=s29 + sink(s.unquote(source("s30"), "quote")); // $ MISSING: hasTaintFlow=s30 + sink(s.map(source("s31"), (x) => {return x;})); // $ MISSING: hasTaintFlow=s31 +} From 9bca863e38034c4387bd705b6b0d7cff104916c5 Mon Sep 17 00:00:00 2001 From: Napalys Date: Mon, 17 Mar 2025 12:50:41 +0100 Subject: [PATCH 02/23] Added modeling of `underscore.string` string to string functions. --- .../ql/lib/ext/underscore.string.model.yml | 6 ++ .../TripleDot/underscore.string.js | 62 +++++++++---------- 2 files changed, 37 insertions(+), 31 deletions(-) create mode 100644 javascript/ql/lib/ext/underscore.string.model.yml diff --git a/javascript/ql/lib/ext/underscore.string.model.yml b/javascript/ql/lib/ext/underscore.string.model.yml new file mode 100644 index 000000000000..ae94ebbf1dfe --- /dev/null +++ b/javascript/ql/lib/ext/underscore.string.model.yml @@ -0,0 +1,6 @@ +extensions: + - addsTo: + pack: codeql/javascript-all + extensible: summaryModel + data: + - ["'underscore.string'", "Member[slugify,capitalize,decapitalize,clean,cleanDiacritics,swapCase,escapeHTML,unescapeHTML,wrap,dedent,reverse,pred,succ,titleize,camelize,classify,underscored,dasherize,humanize,trim,ltrim,rtrim,truncate,sprintf,strRight,strRightBack,strLeft,strLeftBack,stripTags,unquote,map]", "Argument[0]", "ReturnValue", "taint"] diff --git a/javascript/ql/test/library-tests/TripleDot/underscore.string.js b/javascript/ql/test/library-tests/TripleDot/underscore.string.js index 618a6e68261e..fa4c9a9e4d1d 100644 --- a/javascript/ql/test/library-tests/TripleDot/underscore.string.js +++ b/javascript/ql/test/library-tests/TripleDot/underscore.string.js @@ -1,35 +1,35 @@ var s = require("underscore.string"); function strToStr() { - sink(s.slugify(source("s1"))); // $ MISSING: hasTaintFlow=s1 - sink(s.capitalize(source("s2"))); // $ MISSING: hasTaintFlow=s2 - sink(s.decapitalize(source("s3"))); // $ MISSING: hasTaintFlow=s3 - sink(s.clean(source("s4"))); // $ MISSING: hasTaintFlow=s4 - sink(s.cleanDiacritics(source("s5"))); // $ MISSING: hasTaintFlow=s5 - sink(s.swapCase(source("s6"))); // $ MISSING: hasTaintFlow=s6 - sink(s.escapeHTML(source("s7"))); // $ MISSING: hasTaintFlow=s7 - sink(s.unescapeHTML(source("s8"))); // $ MISSING: hasTaintFlow=s8 - sink(s.wrap(source("s9"), {})); // $ MISSING: hasTaintFlow=s9 - sink(s.dedent(source("s10"), " ")); // $ MISSING: hasTaintFlow=s10 - sink(s.reverse(source("s11"))); // $ MISSING: hasTaintFlow=s11 - sink(s.pred(source("s12"))); // $ MISSING: hasTaintFlow=s12 - sink(s.succ(source("s13"))); // $ MISSING: hasTaintFlow=s13 - sink(s.titleize(source("s14"))); // $ MISSING: hasTaintFlow=s14 - sink(s.camelize(source("s15"))); // $ MISSING: hasTaintFlow=s15 - sink(s.classify(source("s16"))); // $ MISSING: hasTaintFlow=s16 - sink(s.underscored(source("s17"))); // $ MISSING: hasTaintFlow=s17 - sink(s.dasherize(source("s18"))); // $ MISSING: hasTaintFlow=s18 - sink(s.humanize(source("s19"))); // $ MISSING: hasTaintFlow=s19 - sink(s.trim(source("s20"),"charsToStrim")); // $ MISSING: hasTaintFlow=s20 - sink(s.ltrim(source("s21"),"charsToStrim")); // $ MISSING: hasTaintFlow=s21 - sink(s.rtrim(source("s22"),"charsToStrim")); // $ MISSING: hasTaintFlow=s22 - sink(s.truncate(source("s23"), 10)); // $ MISSING: hasTaintFlow=s23 - sink(s.sprintf(source("s24"), 1.17)); // $ MISSING: hasTaintFlow=s24 - sink(s.strRight(source("s25"), "pattern")); // $ MISSING: hasTaintFlow=s25 - sink(s.strRightBack(source("s26"), "pattern")); // $ MISSING: hasTaintFlow=s26 - sink(s.strLeft(source("s27"), "pattern")); // $ MISSING: hasTaintFlow=s27 - sink(s.strLeftBack(source("s28"), "pattern")); // $ MISSING: hasTaintFlow=s28 - sink(s.stripTags(source("s29"))); // $ MISSING: hasTaintFlow=s29 - sink(s.unquote(source("s30"), "quote")); // $ MISSING: hasTaintFlow=s30 - sink(s.map(source("s31"), (x) => {return x;})); // $ MISSING: hasTaintFlow=s31 + sink(s.slugify(source("s1"))); // $ hasTaintFlow=s1 + sink(s.capitalize(source("s2"))); // $ hasTaintFlow=s2 + sink(s.decapitalize(source("s3"))); // $ hasTaintFlow=s3 + sink(s.clean(source("s4"))); // $ hasTaintFlow=s4 + sink(s.cleanDiacritics(source("s5"))); // $ hasTaintFlow=s5 + sink(s.swapCase(source("s6"))); // $ hasTaintFlow=s6 + sink(s.escapeHTML(source("s7"))); // $ hasTaintFlow=s7 + sink(s.unescapeHTML(source("s8"))); // $ hasTaintFlow=s8 + sink(s.wrap(source("s9"), {})); // $ hasTaintFlow=s9 + sink(s.dedent(source("s10"), " ")); // $ hasTaintFlow=s10 + sink(s.reverse(source("s11"))); // $ hasTaintFlow=s11 + sink(s.pred(source("s12"))); // $ hasTaintFlow=s12 + sink(s.succ(source("s13"))); // $ hasTaintFlow=s13 + sink(s.titleize(source("s14"))); // $ hasTaintFlow=s14 + sink(s.camelize(source("s15"))); // $ hasTaintFlow=s15 + sink(s.classify(source("s16"))); // $ hasTaintFlow=s16 + sink(s.underscored(source("s17"))); // $ hasTaintFlow=s17 + sink(s.dasherize(source("s18"))); // $ hasTaintFlow=s18 + sink(s.humanize(source("s19"))); // $ hasTaintFlow=s19 + sink(s.trim(source("s20"),"charsToStrim")); // $ hasTaintFlow=s20 + sink(s.ltrim(source("s21"),"charsToStrim")); // $ hasTaintFlow=s21 + sink(s.rtrim(source("s22"),"charsToStrim")); // $ hasTaintFlow=s22 + sink(s.truncate(source("s23"), 10)); // $ hasTaintFlow=s23 + sink(s.sprintf(source("s24"), 1.17)); // $ hasTaintFlow=s24 + sink(s.strRight(source("s25"), "pattern")); // $ hasTaintFlow=s25 + sink(s.strRightBack(source("s26"), "pattern")); // $ hasTaintFlow=s26 + sink(s.strLeft(source("s27"), "pattern")); // $ hasTaintFlow=s27 + sink(s.strLeftBack(source("s28"), "pattern")); // $ hasTaintFlow=s28 + sink(s.stripTags(source("s29"))); // $ hasTaintFlow=s29 + sink(s.unquote(source("s30"), "quote")); // $ hasTaintFlow=s30 + sink(s.map(source("s31"), (x) => {return x;})); // $ hasTaintFlow=s31 } From c256b9c336e79513936877ad08e6e38899930794 Mon Sep 17 00:00:00 2001 From: Napalys Date: Mon, 17 Mar 2025 12:51:48 +0100 Subject: [PATCH 03/23] Added `underscore.string` test cases for str to array. --- .../ql/test/library-tests/TripleDot/underscore.string.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/javascript/ql/test/library-tests/TripleDot/underscore.string.js b/javascript/ql/test/library-tests/TripleDot/underscore.string.js index fa4c9a9e4d1d..4ea59d0b7ff1 100644 --- a/javascript/ql/test/library-tests/TripleDot/underscore.string.js +++ b/javascript/ql/test/library-tests/TripleDot/underscore.string.js @@ -33,3 +33,10 @@ function strToStr() { sink(s.unquote(source("s30"), "quote")); // $ hasTaintFlow=s30 sink(s.map(source("s31"), (x) => {return x;})); // $ hasTaintFlow=s31 } + +function strToArray() { + sink(s.chop(source("s1"), 3)[0]); // $ MISSING: hasTaintFlow=s1 + sink(s.chars(source("s2")[0])); // $ MISSING: hasTaintFlow=s2 + sink(s.words(source("s3")[0])); // $ MISSING: hasTaintFlow=s3 + sink(s.lines(source("s7")[0])); // $ MISSING: hasTaintFlow=s7 +} From 30623cd953262d53e76acb3669aff4eb784ba877 Mon Sep 17 00:00:00 2001 From: Napalys Date: Mon, 17 Mar 2025 12:52:56 +0100 Subject: [PATCH 04/23] Added modeling of `underscore.string` for str to array. --- javascript/ql/lib/ext/underscore.string.model.yml | 1 + .../ql/test/library-tests/TripleDot/underscore.string.js | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/javascript/ql/lib/ext/underscore.string.model.yml b/javascript/ql/lib/ext/underscore.string.model.yml index ae94ebbf1dfe..9061527ab56a 100644 --- a/javascript/ql/lib/ext/underscore.string.model.yml +++ b/javascript/ql/lib/ext/underscore.string.model.yml @@ -4,3 +4,4 @@ extensions: extensible: summaryModel data: - ["'underscore.string'", "Member[slugify,capitalize,decapitalize,clean,cleanDiacritics,swapCase,escapeHTML,unescapeHTML,wrap,dedent,reverse,pred,succ,titleize,camelize,classify,underscored,dasherize,humanize,trim,ltrim,rtrim,truncate,sprintf,strRight,strRightBack,strLeft,strLeftBack,stripTags,unquote,map]", "Argument[0]", "ReturnValue", "taint"] + - ["'underscore.string'", "Member[chop,chars,words,lines]", "Argument[0]", "ReturnValue", "taint"] diff --git a/javascript/ql/test/library-tests/TripleDot/underscore.string.js b/javascript/ql/test/library-tests/TripleDot/underscore.string.js index 4ea59d0b7ff1..ea8f88cbac54 100644 --- a/javascript/ql/test/library-tests/TripleDot/underscore.string.js +++ b/javascript/ql/test/library-tests/TripleDot/underscore.string.js @@ -35,8 +35,8 @@ function strToStr() { } function strToArray() { - sink(s.chop(source("s1"), 3)[0]); // $ MISSING: hasTaintFlow=s1 - sink(s.chars(source("s2")[0])); // $ MISSING: hasTaintFlow=s2 - sink(s.words(source("s3")[0])); // $ MISSING: hasTaintFlow=s3 - sink(s.lines(source("s7")[0])); // $ MISSING: hasTaintFlow=s7 + sink(s.chop(source("s1"), 3)[0]); // $ hasTaintFlow=s1 + sink(s.chars(source("s2")[0])); // $ hasTaintFlow=s2 + sink(s.words(source("s3")[0])); // $ hasTaintFlow=s3 + sink(s.lines(source("s7")[0])); // $ hasTaintFlow=s7 } From cd40b6f125016e8bdd91a71bf0e7b2d3a41df410 Mon Sep 17 00:00:00 2001 From: Napalys Date: Mon, 17 Mar 2025 12:53:53 +0100 Subject: [PATCH 05/23] Added test cases `underscore.string` array to string. --- .../ql/test/library-tests/TripleDot/underscore.string.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/javascript/ql/test/library-tests/TripleDot/underscore.string.js b/javascript/ql/test/library-tests/TripleDot/underscore.string.js index ea8f88cbac54..914ac2b3f14c 100644 --- a/javascript/ql/test/library-tests/TripleDot/underscore.string.js +++ b/javascript/ql/test/library-tests/TripleDot/underscore.string.js @@ -40,3 +40,8 @@ function strToArray() { sink(s.words(source("s3")[0])); // $ hasTaintFlow=s3 sink(s.lines(source("s7")[0])); // $ hasTaintFlow=s7 } + +function arrayToStr() { + sink(s.toSentence([source("s1")])); // $ MISSING: hasTaintFlow=s1 + sink(s.toSentenceSerial([source("s2")])); // $ MISSING: hasTaintFlow=s2 +} From 6b105b2f496351a3ea5328e892b576cf081b2f96 Mon Sep 17 00:00:00 2001 From: Napalys Date: Mon, 17 Mar 2025 12:55:53 +0100 Subject: [PATCH 06/23] Added modeling `underscore.string` array to string functions. --- javascript/ql/lib/ext/underscore.string.model.yml | 1 + .../ql/test/library-tests/TripleDot/underscore.string.js | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/javascript/ql/lib/ext/underscore.string.model.yml b/javascript/ql/lib/ext/underscore.string.model.yml index 9061527ab56a..a1a25016d21a 100644 --- a/javascript/ql/lib/ext/underscore.string.model.yml +++ b/javascript/ql/lib/ext/underscore.string.model.yml @@ -5,3 +5,4 @@ extensions: data: - ["'underscore.string'", "Member[slugify,capitalize,decapitalize,clean,cleanDiacritics,swapCase,escapeHTML,unescapeHTML,wrap,dedent,reverse,pred,succ,titleize,camelize,classify,underscored,dasherize,humanize,trim,ltrim,rtrim,truncate,sprintf,strRight,strRightBack,strLeft,strLeftBack,stripTags,unquote,map]", "Argument[0]", "ReturnValue", "taint"] - ["'underscore.string'", "Member[chop,chars,words,lines]", "Argument[0]", "ReturnValue", "taint"] + - ["'underscore.string'", "Member[toSentence,toSentenceSerial]", "Argument[0].ArrayElement", "ReturnValue", "taint"] diff --git a/javascript/ql/test/library-tests/TripleDot/underscore.string.js b/javascript/ql/test/library-tests/TripleDot/underscore.string.js index 914ac2b3f14c..6a74e74fb194 100644 --- a/javascript/ql/test/library-tests/TripleDot/underscore.string.js +++ b/javascript/ql/test/library-tests/TripleDot/underscore.string.js @@ -42,6 +42,6 @@ function strToArray() { } function arrayToStr() { - sink(s.toSentence([source("s1")])); // $ MISSING: hasTaintFlow=s1 - sink(s.toSentenceSerial([source("s2")])); // $ MISSING: hasTaintFlow=s2 + sink(s.toSentence([source("s1")])); // $ hasTaintFlow=s1 + sink(s.toSentenceSerial([source("s2")])); // $ hasTaintFlow=s2 } From 77e1e171e1754f5448d9d30af6e525aa74b938fe Mon Sep 17 00:00:00 2001 From: Napalys Date: Mon, 17 Mar 2025 12:58:53 +0100 Subject: [PATCH 07/23] Added test cases `underscore.string` with multiple sources. --- .../TripleDot/underscore.string.js | 37 ++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/javascript/ql/test/library-tests/TripleDot/underscore.string.js b/javascript/ql/test/library-tests/TripleDot/underscore.string.js index 6a74e74fb194..2006171f2e1c 100644 --- a/javascript/ql/test/library-tests/TripleDot/underscore.string.js +++ b/javascript/ql/test/library-tests/TripleDot/underscore.string.js @@ -11,7 +11,7 @@ function strToStr() { sink(s.unescapeHTML(source("s8"))); // $ hasTaintFlow=s8 sink(s.wrap(source("s9"), {})); // $ hasTaintFlow=s9 sink(s.dedent(source("s10"), " ")); // $ hasTaintFlow=s10 - sink(s.reverse(source("s11"))); // $ hasTaintFlow=s11 + sink(s.reverse(source("s11"))); // $ hasTaintFlow=s11 SPURIOUS: hasTaintFlow=s8 sink(s.pred(source("s12"))); // $ hasTaintFlow=s12 sink(s.succ(source("s13"))); // $ hasTaintFlow=s13 sink(s.titleize(source("s14"))); // $ hasTaintFlow=s14 @@ -45,3 +45,38 @@ function arrayToStr() { sink(s.toSentence([source("s1")])); // $ hasTaintFlow=s1 sink(s.toSentenceSerial([source("s2")])); // $ hasTaintFlow=s2 } + +function multiSource() { + sink(s.insert("str", 4, source("s1"))); // $ MISSING: hasTaintFlow=s1 + sink(s.insert(source("s2"), 4, "")); // $ MISSING: hasTaintFlow=s2 + + sink(s.replaceAll("astr", "a", source("s3"))); // $ MISSING: hasTaintFlow=s3 + sink(s.replaceAll(source("s4"), "a", "")); // $ MISSING: hasTaintFlow=s4 + + sink(s.join(",", source("s5"), "str")); // $ MISSING: hasTaintFlow=s5 + sink(s.join(",", "str", source("s6"))); // $ MISSING: hasTaintFlow=s6 + + sink(s.splice(source("s7"), 1, 2, "str")); // $ MISSING: hasTaintFlow=s7 SPURIOUS: hasTaintFlow=s8 + sink(s.splice("str", 1, 2, source("s8"))); // $ SPURIOUS: hasTaintFlow=s8 + + sink(s.prune(source("s9"), 1, "additional")); // $ MISSING: hasTaintFlow=s9 + sink(s.prune("base", 1, source("s10"))); // $ MISSING: hasTaintFlow=s10 + + sink(s.pad(source("s11"), 10, "charsToPad", "right")); // $ MISSING: hasTaintFlow=s11 + sink(s.pad("base", 10, source("s12"), "right")); // $ MISSING: hasTaintFlow=s12 + + sink(s.lpad(source("s13"), 10, "charsToPad")); // $ MISSING: hasTaintFlow=s13 + sink(s.lpad("base", 10, source("s14"))); // $ MISSING: hasTaintFlow=s14 + + sink(s.rpad(source("s15"), 10, "charsToPad")); // $ MISSING: hasTaintFlow=s15 + sink(s.rpad("base", 10, source("s16"))); // $ MISSING: hasTaintFlow=s16 + + sink(s.repeat(source("s17"), 3, "seperator")); // $ MISSING: hasTaintFlow=s17 + sink(s.repeat("base", 3, source("s18"))); // $ MISSING: hasTaintFlow=s18 + + sink(s.surround(source("s19"), "wrap")); // $ MISSING: hasTaintFlow=s19 + sink(s.surround("base", source("s20"))); // $ MISSING: hasTaintFlow=s20 + + sink(s.quote(source("s21"), "quote")); // $ MISSING: hasTaintFlow=s21 + sink(s.quote("base", source("s22"))); // $ MISSING: hasTaintFlow=s22 +} From b59b9c86e45ef18ad314c5de6856a8ea747d3126 Mon Sep 17 00:00:00 2001 From: Napalys Date: Mon, 17 Mar 2025 13:01:53 +0100 Subject: [PATCH 08/23] Added modeling `underscore.string` of function which contain multiple sources points. --- .../ql/lib/ext/underscore.string.model.yml | 4 ++ .../TripleDot/underscore.string.js | 44 +++++++++---------- 2 files changed, 26 insertions(+), 22 deletions(-) diff --git a/javascript/ql/lib/ext/underscore.string.model.yml b/javascript/ql/lib/ext/underscore.string.model.yml index a1a25016d21a..2afe1b1c5557 100644 --- a/javascript/ql/lib/ext/underscore.string.model.yml +++ b/javascript/ql/lib/ext/underscore.string.model.yml @@ -6,3 +6,7 @@ extensions: - ["'underscore.string'", "Member[slugify,capitalize,decapitalize,clean,cleanDiacritics,swapCase,escapeHTML,unescapeHTML,wrap,dedent,reverse,pred,succ,titleize,camelize,classify,underscored,dasherize,humanize,trim,ltrim,rtrim,truncate,sprintf,strRight,strRightBack,strLeft,strLeftBack,stripTags,unquote,map]", "Argument[0]", "ReturnValue", "taint"] - ["'underscore.string'", "Member[chop,chars,words,lines]", "Argument[0]", "ReturnValue", "taint"] - ["'underscore.string'", "Member[toSentence,toSentenceSerial]", "Argument[0].ArrayElement", "ReturnValue", "taint"] + - ["'underscore.string'", "Member[insert,replaceAll,splice,prune,pad,lpad,rpad,repeat]", "Argument[0,2]", "ReturnValue", "taint"] + - ["'underscore.string'", "Member[splice]", "Argument[0,3]", "ReturnValue", "taint"] + - ["'underscore.string'", "Member[join]", "Argument[0..N-1]", "ReturnValue", "taint"] + - ["'underscore.string'", "Member[surround,quote]", "Argument[0,1]", "ReturnValue", "taint"] diff --git a/javascript/ql/test/library-tests/TripleDot/underscore.string.js b/javascript/ql/test/library-tests/TripleDot/underscore.string.js index 2006171f2e1c..34c7aec56c69 100644 --- a/javascript/ql/test/library-tests/TripleDot/underscore.string.js +++ b/javascript/ql/test/library-tests/TripleDot/underscore.string.js @@ -47,36 +47,36 @@ function arrayToStr() { } function multiSource() { - sink(s.insert("str", 4, source("s1"))); // $ MISSING: hasTaintFlow=s1 - sink(s.insert(source("s2"), 4, "")); // $ MISSING: hasTaintFlow=s2 + sink(s.insert("str", 4, source("s1"))); // $ hasTaintFlow=s1 + sink(s.insert(source("s2"), 4, "")); // $ hasTaintFlow=s2 - sink(s.replaceAll("astr", "a", source("s3"))); // $ MISSING: hasTaintFlow=s3 - sink(s.replaceAll(source("s4"), "a", "")); // $ MISSING: hasTaintFlow=s4 + sink(s.replaceAll("astr", "a", source("s3"))); // $ hasTaintFlow=s3 + sink(s.replaceAll(source("s4"), "a", "")); // $ hasTaintFlow=s4 - sink(s.join(",", source("s5"), "str")); // $ MISSING: hasTaintFlow=s5 - sink(s.join(",", "str", source("s6"))); // $ MISSING: hasTaintFlow=s6 + sink(s.join(",", source("s5"), "str")); // $ hasTaintFlow=s5 + sink(s.join(",", "str", source("s6"))); // $ hasTaintFlow=s6 - sink(s.splice(source("s7"), 1, 2, "str")); // $ MISSING: hasTaintFlow=s7 SPURIOUS: hasTaintFlow=s8 - sink(s.splice("str", 1, 2, source("s8"))); // $ SPURIOUS: hasTaintFlow=s8 + sink(s.splice(source("s7"), 1, 2, "str")); // $ hasTaintFlow=s7 SPURIOUS: hasTaintFlow=s8 + sink(s.splice("str", 1, 2, source("s8"))); // $ hasTaintFlow=s8 - sink(s.prune(source("s9"), 1, "additional")); // $ MISSING: hasTaintFlow=s9 - sink(s.prune("base", 1, source("s10"))); // $ MISSING: hasTaintFlow=s10 + sink(s.prune(source("s9"), 1, "additional")); // $ hasTaintFlow=s9 + sink(s.prune("base", 1, source("s10"))); // $ hasTaintFlow=s10 - sink(s.pad(source("s11"), 10, "charsToPad", "right")); // $ MISSING: hasTaintFlow=s11 - sink(s.pad("base", 10, source("s12"), "right")); // $ MISSING: hasTaintFlow=s12 + sink(s.pad(source("s11"), 10, "charsToPad", "right")); // $ hasTaintFlow=s11 + sink(s.pad("base", 10, source("s12"), "right")); // $ hasTaintFlow=s12 - sink(s.lpad(source("s13"), 10, "charsToPad")); // $ MISSING: hasTaintFlow=s13 - sink(s.lpad("base", 10, source("s14"))); // $ MISSING: hasTaintFlow=s14 + sink(s.lpad(source("s13"), 10, "charsToPad")); // $ hasTaintFlow=s13 + sink(s.lpad("base", 10, source("s14"))); // $ hasTaintFlow=s14 - sink(s.rpad(source("s15"), 10, "charsToPad")); // $ MISSING: hasTaintFlow=s15 - sink(s.rpad("base", 10, source("s16"))); // $ MISSING: hasTaintFlow=s16 + sink(s.rpad(source("s15"), 10, "charsToPad")); // $ hasTaintFlow=s15 + sink(s.rpad("base", 10, source("s16"))); // $ hasTaintFlow=s16 - sink(s.repeat(source("s17"), 3, "seperator")); // $ MISSING: hasTaintFlow=s17 - sink(s.repeat("base", 3, source("s18"))); // $ MISSING: hasTaintFlow=s18 + sink(s.repeat(source("s17"), 3, "seperator")); // $ hasTaintFlow=s17 + sink(s.repeat("base", 3, source("s18"))); // $ hasTaintFlow=s18 - sink(s.surround(source("s19"), "wrap")); // $ MISSING: hasTaintFlow=s19 - sink(s.surround("base", source("s20"))); // $ MISSING: hasTaintFlow=s20 + sink(s.surround(source("s19"), "wrap")); // $ hasTaintFlow=s19 + sink(s.surround("base", source("s20"))); // $ hasTaintFlow=s20 - sink(s.quote(source("s21"), "quote")); // $ MISSING: hasTaintFlow=s21 - sink(s.quote("base", source("s22"))); // $ MISSING: hasTaintFlow=s22 + sink(s.quote(source("s21"), "quote")); // $ hasTaintFlow=s21 + sink(s.quote("base", source("s22"))); // $ hasTaintFlow=s22 } From 25c6fb59df680f6bf6b61eddb1adc428b6c665f5 Mon Sep 17 00:00:00 2001 From: Napalys Date: Mon, 17 Mar 2025 14:43:26 +0100 Subject: [PATCH 09/23] Added chaining tests for `underscore.string` package. --- .../TripleDot/underscore.string.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/javascript/ql/test/library-tests/TripleDot/underscore.string.js b/javascript/ql/test/library-tests/TripleDot/underscore.string.js index 34c7aec56c69..2ad620bf9363 100644 --- a/javascript/ql/test/library-tests/TripleDot/underscore.string.js +++ b/javascript/ql/test/library-tests/TripleDot/underscore.string.js @@ -80,3 +80,21 @@ function multiSource() { sink(s.quote(source("s21"), "quote")); // $ hasTaintFlow=s21 sink(s.quote("base", source("s22"))); // $ hasTaintFlow=s22 } + +function chaining() { + sink(s(source("s1")) + .slugify().capitalize().decapitalize().clean().cleanDiacritics() + .swapCase().escapeHTML().unescapeHTML().wrap().dedent() + .reverse().pred().succ().titleize().camelize().classify() + .underscored().dasherize().humanize().trim().ltrim().rtrim() + .truncate().sprintf().strRight().strRightBack() + .strLeft().strLeftBack().stripTags().unquote().value()); // $ MISSING: hasTaintFlow=s1 + + sink(s(source("s2")) + .insert(4, source("s3")).replaceAll("a", source("s4")) + .join(",", source("s5")).splice(1, 2, source("s6")) + .prune(1, source("s7")).pad(10, source("s8"), "right") + .lpad(10, source("s9")).rpad(10, source("s10")) + .repeat(3, source("s11")).surround(source("s12")) + .quote(source("s13")).value()); // $ MISSING: hasTaintFlow=s2 MISSING: hasTaintFlow=s3 MISSING: hasTaintFlow=s4 MISSING: hasTaintFlow=s5 MISSING: hasTaintFlow=s6 MISSING: hasTaintFlow=s7 MISSING: hasTaintFlow=s8 MISSING: hasTaintFlow=s9 MISSING: hasTaintFlow=s10 MISSING: hasTaintFlow=s11 MISSING: hasTaintFlow=s12 MISSING: hasTaintFlow=s13 +} From ca9ae8a58d9dd66fc074873206b7f7fc3b7156ff Mon Sep 17 00:00:00 2001 From: Napalys Date: Mon, 17 Mar 2025 14:44:37 +0100 Subject: [PATCH 10/23] Added chaining modeling for `underscore.string` package. --- javascript/ql/lib/ext/underscore.string.model.yml | 15 +++++++++++++++ .../library-tests/TripleDot/underscore.string.js | 4 ++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/javascript/ql/lib/ext/underscore.string.model.yml b/javascript/ql/lib/ext/underscore.string.model.yml index 2afe1b1c5557..92ec86b48004 100644 --- a/javascript/ql/lib/ext/underscore.string.model.yml +++ b/javascript/ql/lib/ext/underscore.string.model.yml @@ -1,4 +1,12 @@ extensions: + - addsTo: + pack: codeql/javascript-all + extensible: typeModel + data: + - ["'underscore.string'.Wrapper", "'underscore.string'", "ReturnValue"] + - ["'underscore.string'.Wrapper", "'underscore.string'.Wrapper", "Member[slugify,capitalize,decapitalize,clean,cleanDiacritics,swapCase,escapeHTML,unescapeHTML,wrap,dedent,reverse,pred,succ,titleize,camelize,classify,underscored,dasherize,humanize,trim,ltrim,rtrim,truncate,sprintf,strRight,strRightBack,strLeft,strLeftBack,stripTags,unquote,value].ReturnValue"] + - ["'underscore.string'.Wrapper", "'underscore.string'.Wrapper", "Member[insert,replaceAll,join,splice,prune,pad,lpad,rpad,repeat,surround,quote].ReturnValue"] + - addsTo: pack: codeql/javascript-all extensible: summaryModel @@ -10,3 +18,10 @@ extensions: - ["'underscore.string'", "Member[splice]", "Argument[0,3]", "ReturnValue", "taint"] - ["'underscore.string'", "Member[join]", "Argument[0..N-1]", "ReturnValue", "taint"] - ["'underscore.string'", "Member[surround,quote]", "Argument[0,1]", "ReturnValue", "taint"] + - ["'underscore.string'", "", "Argument[0]", "ReturnValue", "taint"] + - ["'underscore.string'.Wrapper", "Member[slugify,capitalize,decapitalize,clean,cleanDiacritics,swapCase,escapeHTML,unescapeHTML,wrap,dedent,reverse,pred,succ,titleize,camelize,classify,underscored,dasherize,humanize,trim,ltrim,rtrim,truncate,sprintf,strRight,strRightBack,strLeft,strLeftBack,stripTags,unquote,value]", "Argument[this]", "ReturnValue", "taint"] + - ["'underscore.string'.Wrapper", "Member[insert,replaceAll,join,splice,prune,pad,lpad,rpad,repeat,surround,quote]", "Argument[this]", "ReturnValue", "taint"] + - ["'underscore.string'.Wrapper", "Member[insert,replaceAll,prune,pad,lpad,rpad,repeat]", "Argument[1]", "ReturnValue", "taint"] + - ["'underscore.string'.Wrapper", "Member[surround,quote]", "Argument[0]", "ReturnValue", "taint"] + - ["'underscore.string'.Wrapper", "Member[splice]", "Argument[2]", "ReturnValue", "taint"] + - ["'underscore.string'.Wrapper", "Member[join]", "Argument[0..N-1]", "ReturnValue", "taint"] diff --git a/javascript/ql/test/library-tests/TripleDot/underscore.string.js b/javascript/ql/test/library-tests/TripleDot/underscore.string.js index 2ad620bf9363..22c798076fc3 100644 --- a/javascript/ql/test/library-tests/TripleDot/underscore.string.js +++ b/javascript/ql/test/library-tests/TripleDot/underscore.string.js @@ -88,7 +88,7 @@ function chaining() { .reverse().pred().succ().titleize().camelize().classify() .underscored().dasherize().humanize().trim().ltrim().rtrim() .truncate().sprintf().strRight().strRightBack() - .strLeft().strLeftBack().stripTags().unquote().value()); // $ MISSING: hasTaintFlow=s1 + .strLeft().strLeftBack().stripTags().unquote().value()); // $ hasTaintFlow=s1 sink(s(source("s2")) .insert(4, source("s3")).replaceAll("a", source("s4")) @@ -96,5 +96,5 @@ function chaining() { .prune(1, source("s7")).pad(10, source("s8"), "right") .lpad(10, source("s9")).rpad(10, source("s10")) .repeat(3, source("s11")).surround(source("s12")) - .quote(source("s13")).value()); // $ MISSING: hasTaintFlow=s2 MISSING: hasTaintFlow=s3 MISSING: hasTaintFlow=s4 MISSING: hasTaintFlow=s5 MISSING: hasTaintFlow=s6 MISSING: hasTaintFlow=s7 MISSING: hasTaintFlow=s8 MISSING: hasTaintFlow=s9 MISSING: hasTaintFlow=s10 MISSING: hasTaintFlow=s11 MISSING: hasTaintFlow=s12 MISSING: hasTaintFlow=s13 + .quote(source("s13")).value()); // $ hasTaintFlow=s2 hasTaintFlow=s3 hasTaintFlow=s4 hasTaintFlow=s5 hasTaintFlow=s6 hasTaintFlow=s7 hasTaintFlow=s8 hasTaintFlow=s9 hasTaintFlow=s10 hasTaintFlow=s11 hasTaintFlow=s12 hasTaintFlow=s13 } From cccd863a96c4751b4c1d4d09450ae6a06c52fbf7 Mon Sep 17 00:00:00 2001 From: Napalys Date: Mon, 17 Mar 2025 18:05:49 +0100 Subject: [PATCH 11/23] Added test for extra chaining function for `underscore.string`. --- .../ql/test/library-tests/TripleDot/underscore.string.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/javascript/ql/test/library-tests/TripleDot/underscore.string.js b/javascript/ql/test/library-tests/TripleDot/underscore.string.js index 22c798076fc3..6ef5f1cb59a3 100644 --- a/javascript/ql/test/library-tests/TripleDot/underscore.string.js +++ b/javascript/ql/test/library-tests/TripleDot/underscore.string.js @@ -97,4 +97,7 @@ function chaining() { .lpad(10, source("s9")).rpad(10, source("s10")) .repeat(3, source("s11")).surround(source("s12")) .quote(source("s13")).value()); // $ hasTaintFlow=s2 hasTaintFlow=s3 hasTaintFlow=s4 hasTaintFlow=s5 hasTaintFlow=s6 hasTaintFlow=s7 hasTaintFlow=s8 hasTaintFlow=s9 hasTaintFlow=s10 hasTaintFlow=s11 hasTaintFlow=s12 hasTaintFlow=s13 + + sink(s(source("s14")).toUpperCase().toLowerCase().replace().slice(1).substring(1).substr(1).concat(source("s15")).split()); // $ MISSING: hasTaintFlow=s14 MISSING: hasTaintFlow=s15 + } From 3a83c8d1fddebcb416b970ebc4f11ef2841703b9 Mon Sep 17 00:00:00 2001 From: Napalys Date: Mon, 17 Mar 2025 18:06:26 +0100 Subject: [PATCH 12/23] Added modeling for extra chaining function from `underscore.string`. --- javascript/ql/lib/ext/underscore.string.model.yml | 4 +++- .../ql/test/library-tests/TripleDot/underscore.string.js | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/javascript/ql/lib/ext/underscore.string.model.yml b/javascript/ql/lib/ext/underscore.string.model.yml index 92ec86b48004..619401890b54 100644 --- a/javascript/ql/lib/ext/underscore.string.model.yml +++ b/javascript/ql/lib/ext/underscore.string.model.yml @@ -6,6 +6,7 @@ extensions: - ["'underscore.string'.Wrapper", "'underscore.string'", "ReturnValue"] - ["'underscore.string'.Wrapper", "'underscore.string'.Wrapper", "Member[slugify,capitalize,decapitalize,clean,cleanDiacritics,swapCase,escapeHTML,unescapeHTML,wrap,dedent,reverse,pred,succ,titleize,camelize,classify,underscored,dasherize,humanize,trim,ltrim,rtrim,truncate,sprintf,strRight,strRightBack,strLeft,strLeftBack,stripTags,unquote,value].ReturnValue"] - ["'underscore.string'.Wrapper", "'underscore.string'.Wrapper", "Member[insert,replaceAll,join,splice,prune,pad,lpad,rpad,repeat,surround,quote].ReturnValue"] + - ["'underscore.string'.Wrapper", "'underscore.string'.Wrapper", "Member[toUpperCase,toLowerCase,replace,slice,substring,substr,concat].ReturnValue"] - addsTo: pack: codeql/javascript-all @@ -24,4 +25,5 @@ extensions: - ["'underscore.string'.Wrapper", "Member[insert,replaceAll,prune,pad,lpad,rpad,repeat]", "Argument[1]", "ReturnValue", "taint"] - ["'underscore.string'.Wrapper", "Member[surround,quote]", "Argument[0]", "ReturnValue", "taint"] - ["'underscore.string'.Wrapper", "Member[splice]", "Argument[2]", "ReturnValue", "taint"] - - ["'underscore.string'.Wrapper", "Member[join]", "Argument[0..N-1]", "ReturnValue", "taint"] + - ["'underscore.string'.Wrapper", "Member[join,concat]", "Argument[0..N-1]", "ReturnValue", "taint"] + - ["'underscore.string'.Wrapper", "Member[toUpperCase,toLowerCase,replace,slice,substring,substr,split]", "Argument[this]", "ReturnValue", "taint"] diff --git a/javascript/ql/test/library-tests/TripleDot/underscore.string.js b/javascript/ql/test/library-tests/TripleDot/underscore.string.js index 6ef5f1cb59a3..afeb8cc6dfb0 100644 --- a/javascript/ql/test/library-tests/TripleDot/underscore.string.js +++ b/javascript/ql/test/library-tests/TripleDot/underscore.string.js @@ -98,6 +98,6 @@ function chaining() { .repeat(3, source("s11")).surround(source("s12")) .quote(source("s13")).value()); // $ hasTaintFlow=s2 hasTaintFlow=s3 hasTaintFlow=s4 hasTaintFlow=s5 hasTaintFlow=s6 hasTaintFlow=s7 hasTaintFlow=s8 hasTaintFlow=s9 hasTaintFlow=s10 hasTaintFlow=s11 hasTaintFlow=s12 hasTaintFlow=s13 - sink(s(source("s14")).toUpperCase().toLowerCase().replace().slice(1).substring(1).substr(1).concat(source("s15")).split()); // $ MISSING: hasTaintFlow=s14 MISSING: hasTaintFlow=s15 + sink(s(source("s14")).toUpperCase().toLowerCase().replace().slice(1).substring(1).substr(1).concat(source("s15")).split()); // $ hasTaintFlow=s14 hasTaintFlow=s15 } From dcc1e88d088e227769e539c5b67074890854cb28 Mon Sep 17 00:00:00 2001 From: Napalys Date: Mon, 17 Mar 2025 18:23:46 +0100 Subject: [PATCH 13/23] Added test cases for aliases. --- .../TripleDot/underscore.string.js | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/javascript/ql/test/library-tests/TripleDot/underscore.string.js b/javascript/ql/test/library-tests/TripleDot/underscore.string.js index afeb8cc6dfb0..2c7d7a3e1d24 100644 --- a/javascript/ql/test/library-tests/TripleDot/underscore.string.js +++ b/javascript/ql/test/library-tests/TripleDot/underscore.string.js @@ -32,6 +32,10 @@ function strToStr() { sink(s.stripTags(source("s29"))); // $ hasTaintFlow=s29 sink(s.unquote(source("s30"), "quote")); // $ hasTaintFlow=s30 sink(s.map(source("s31"), (x) => {return x;})); // $ hasTaintFlow=s31 + sink(s.strip(source("s32"),"charsToStrim")); // $ MISSING: hasTaintFlow=s32 + sink(s.lstrip(source("s33"),"charsToStrim")); // $ MISSING: hasTaintFlow=s33 + sink(s.rstrip(source("s34"),"charsToStrim")); // $ MISSING: hasTaintFlow=s34 + sink(s.camelcase(source("s35"))); // $ MISSING: hasTaintFlow=s35 } function strToArray() { @@ -79,6 +83,15 @@ function multiSource() { sink(s.quote(source("s21"), "quote")); // $ hasTaintFlow=s21 sink(s.quote("base", source("s22"))); // $ hasTaintFlow=s22 + + sink(s.q(source("s23"), "quote")); // $ MISSING: hasTaintFlow=s23 + sink(s.q("base", source("s24"))); // $ MISSING: hasTaintFlow=s24 + + sink(s.rjust(source("s25"), 10, "charsToPad")); // $ MISSING: hasTaintFlow=s25 + sink(s.rjust("base", 10, source("s26"))); // $ MISSING: hasTaintFlow=s26 + + sink(s.ljust(source("s27"), 10, "charsToPad")); // $ MISSING: hasTaintFlow=s27 + sink(s.ljust("base", 10, source("s28"))); // $ MISSING: hasTaintFlow=s28 } function chaining() { @@ -100,4 +113,8 @@ function chaining() { sink(s(source("s14")).toUpperCase().toLowerCase().replace().slice(1).substring(1).substr(1).concat(source("s15")).split()); // $ hasTaintFlow=s14 hasTaintFlow=s15 + sink(s(source("s16")) + .strip().lstrip().rstrip().camelcase() + .q(source("s17").ljust(10, source("s18")) + .rjust(10, source("s19")))); // $ MISSING: hasTaintFlow=s16 MISSING: hasTaintFlow=s17 MISSING: hasTaintFlow=s18 MISSING: hasTaintFlow=s19 } From fc6b779a4b623894f660b95b79b54aba274a47bf Mon Sep 17 00:00:00 2001 From: Napalys Date: Mon, 17 Mar 2025 18:33:14 +0100 Subject: [PATCH 14/23] Added modeling for aliases. --- .../ql/lib/ext/underscore.string.model.yml | 18 +++++++------- .../TripleDot/underscore.string.js | 24 +++++++++---------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/javascript/ql/lib/ext/underscore.string.model.yml b/javascript/ql/lib/ext/underscore.string.model.yml index 619401890b54..77c73d407f0c 100644 --- a/javascript/ql/lib/ext/underscore.string.model.yml +++ b/javascript/ql/lib/ext/underscore.string.model.yml @@ -4,26 +4,26 @@ extensions: extensible: typeModel data: - ["'underscore.string'.Wrapper", "'underscore.string'", "ReturnValue"] - - ["'underscore.string'.Wrapper", "'underscore.string'.Wrapper", "Member[slugify,capitalize,decapitalize,clean,cleanDiacritics,swapCase,escapeHTML,unescapeHTML,wrap,dedent,reverse,pred,succ,titleize,camelize,classify,underscored,dasherize,humanize,trim,ltrim,rtrim,truncate,sprintf,strRight,strRightBack,strLeft,strLeftBack,stripTags,unquote,value].ReturnValue"] - - ["'underscore.string'.Wrapper", "'underscore.string'.Wrapper", "Member[insert,replaceAll,join,splice,prune,pad,lpad,rpad,repeat,surround,quote].ReturnValue"] + - ["'underscore.string'.Wrapper", "'underscore.string'.Wrapper", "Member[slugify,capitalize,decapitalize,clean,cleanDiacritics,swapCase,escapeHTML,unescapeHTML,wrap,dedent,reverse,pred,succ,titleize,camelize,classify,underscored,dasherize,humanize,trim,ltrim,rtrim,truncate,sprintf,strRight,strRightBack,strLeft,strLeftBack,stripTags,unquote,value,strip,lstrip,rstrip,camelcase].ReturnValue"] + - ["'underscore.string'.Wrapper", "'underscore.string'.Wrapper", "Member[insert,replaceAll,join,splice,prune,pad,lpad,rpad,repeat,surround,quote,q,rjust,ljust].ReturnValue"] - ["'underscore.string'.Wrapper", "'underscore.string'.Wrapper", "Member[toUpperCase,toLowerCase,replace,slice,substring,substr,concat].ReturnValue"] - addsTo: pack: codeql/javascript-all extensible: summaryModel data: - - ["'underscore.string'", "Member[slugify,capitalize,decapitalize,clean,cleanDiacritics,swapCase,escapeHTML,unescapeHTML,wrap,dedent,reverse,pred,succ,titleize,camelize,classify,underscored,dasherize,humanize,trim,ltrim,rtrim,truncate,sprintf,strRight,strRightBack,strLeft,strLeftBack,stripTags,unquote,map]", "Argument[0]", "ReturnValue", "taint"] + - ["'underscore.string'", "Member[slugify,capitalize,decapitalize,clean,cleanDiacritics,swapCase,escapeHTML,unescapeHTML,wrap,dedent,reverse,pred,succ,titleize,camelize,classify,underscored,dasherize,humanize,trim,ltrim,rtrim,truncate,sprintf,strRight,strRightBack,strLeft,strLeftBack,stripTags,unquote,map,strip,lstrip,rstrip,camelcase]", "Argument[0]", "ReturnValue", "taint"] - ["'underscore.string'", "Member[chop,chars,words,lines]", "Argument[0]", "ReturnValue", "taint"] - ["'underscore.string'", "Member[toSentence,toSentenceSerial]", "Argument[0].ArrayElement", "ReturnValue", "taint"] - - ["'underscore.string'", "Member[insert,replaceAll,splice,prune,pad,lpad,rpad,repeat]", "Argument[0,2]", "ReturnValue", "taint"] + - ["'underscore.string'", "Member[insert,replaceAll,splice,prune,pad,lpad,rpad,repeat,rjust,ljust]", "Argument[0,2]", "ReturnValue", "taint"] - ["'underscore.string'", "Member[splice]", "Argument[0,3]", "ReturnValue", "taint"] - ["'underscore.string'", "Member[join]", "Argument[0..N-1]", "ReturnValue", "taint"] - - ["'underscore.string'", "Member[surround,quote]", "Argument[0,1]", "ReturnValue", "taint"] + - ["'underscore.string'", "Member[surround,quote,q]", "Argument[0,1]", "ReturnValue", "taint"] - ["'underscore.string'", "", "Argument[0]", "ReturnValue", "taint"] - - ["'underscore.string'.Wrapper", "Member[slugify,capitalize,decapitalize,clean,cleanDiacritics,swapCase,escapeHTML,unescapeHTML,wrap,dedent,reverse,pred,succ,titleize,camelize,classify,underscored,dasherize,humanize,trim,ltrim,rtrim,truncate,sprintf,strRight,strRightBack,strLeft,strLeftBack,stripTags,unquote,value]", "Argument[this]", "ReturnValue", "taint"] - - ["'underscore.string'.Wrapper", "Member[insert,replaceAll,join,splice,prune,pad,lpad,rpad,repeat,surround,quote]", "Argument[this]", "ReturnValue", "taint"] - - ["'underscore.string'.Wrapper", "Member[insert,replaceAll,prune,pad,lpad,rpad,repeat]", "Argument[1]", "ReturnValue", "taint"] - - ["'underscore.string'.Wrapper", "Member[surround,quote]", "Argument[0]", "ReturnValue", "taint"] + - ["'underscore.string'.Wrapper", "Member[slugify,capitalize,decapitalize,clean,cleanDiacritics,swapCase,escapeHTML,unescapeHTML,wrap,dedent,reverse,pred,succ,titleize,camelize,classify,underscored,dasherize,humanize,trim,ltrim,rtrim,truncate,sprintf,strRight,strRightBack,strLeft,strLeftBack,stripTags,unquote,value,strip,lstrip,rstrip,camelcase]", "Argument[this]", "ReturnValue", "taint"] + - ["'underscore.string'.Wrapper", "Member[insert,replaceAll,join,splice,prune,pad,lpad,rpad,repeat,surround,quote,q,rjust,ljust]", "Argument[this]", "ReturnValue", "taint"] + - ["'underscore.string'.Wrapper", "Member[insert,replaceAll,prune,pad,lpad,rpad,repeat,rjust,ljust]", "Argument[1]", "ReturnValue", "taint"] + - ["'underscore.string'.Wrapper", "Member[surround,quote,q]", "Argument[0]", "ReturnValue", "taint"] - ["'underscore.string'.Wrapper", "Member[splice]", "Argument[2]", "ReturnValue", "taint"] - ["'underscore.string'.Wrapper", "Member[join,concat]", "Argument[0..N-1]", "ReturnValue", "taint"] - ["'underscore.string'.Wrapper", "Member[toUpperCase,toLowerCase,replace,slice,substring,substr,split]", "Argument[this]", "ReturnValue", "taint"] diff --git a/javascript/ql/test/library-tests/TripleDot/underscore.string.js b/javascript/ql/test/library-tests/TripleDot/underscore.string.js index 2c7d7a3e1d24..66d7dd1b9e75 100644 --- a/javascript/ql/test/library-tests/TripleDot/underscore.string.js +++ b/javascript/ql/test/library-tests/TripleDot/underscore.string.js @@ -32,10 +32,10 @@ function strToStr() { sink(s.stripTags(source("s29"))); // $ hasTaintFlow=s29 sink(s.unquote(source("s30"), "quote")); // $ hasTaintFlow=s30 sink(s.map(source("s31"), (x) => {return x;})); // $ hasTaintFlow=s31 - sink(s.strip(source("s32"),"charsToStrim")); // $ MISSING: hasTaintFlow=s32 - sink(s.lstrip(source("s33"),"charsToStrim")); // $ MISSING: hasTaintFlow=s33 - sink(s.rstrip(source("s34"),"charsToStrim")); // $ MISSING: hasTaintFlow=s34 - sink(s.camelcase(source("s35"))); // $ MISSING: hasTaintFlow=s35 + sink(s.strip(source("s32"),"charsToStrim")); // $ hasTaintFlow=s32 + sink(s.lstrip(source("s33"),"charsToStrim")); // $ hasTaintFlow=s33 + sink(s.rstrip(source("s34"),"charsToStrim")); // $ hasTaintFlow=s34 + sink(s.camelcase(source("s35"))); // $ hasTaintFlow=s35 } function strToArray() { @@ -84,14 +84,14 @@ function multiSource() { sink(s.quote(source("s21"), "quote")); // $ hasTaintFlow=s21 sink(s.quote("base", source("s22"))); // $ hasTaintFlow=s22 - sink(s.q(source("s23"), "quote")); // $ MISSING: hasTaintFlow=s23 - sink(s.q("base", source("s24"))); // $ MISSING: hasTaintFlow=s24 + sink(s.q(source("s23"), "quote")); // $ hasTaintFlow=s23 + sink(s.q("base", source("s24"))); // $ hasTaintFlow=s24 - sink(s.rjust(source("s25"), 10, "charsToPad")); // $ MISSING: hasTaintFlow=s25 - sink(s.rjust("base", 10, source("s26"))); // $ MISSING: hasTaintFlow=s26 + sink(s.rjust(source("s25"), 10, "charsToPad")); // $ hasTaintFlow=s25 + sink(s.rjust("base", 10, source("s26"))); // $ hasTaintFlow=s26 - sink(s.ljust(source("s27"), 10, "charsToPad")); // $ MISSING: hasTaintFlow=s27 - sink(s.ljust("base", 10, source("s28"))); // $ MISSING: hasTaintFlow=s28 + sink(s.ljust(source("s27"), 10, "charsToPad")); // $ hasTaintFlow=s27 + sink(s.ljust("base", 10, source("s28"))); // $ hasTaintFlow=s28 } function chaining() { @@ -115,6 +115,6 @@ function chaining() { sink(s(source("s16")) .strip().lstrip().rstrip().camelcase() - .q(source("s17").ljust(10, source("s18")) - .rjust(10, source("s19")))); // $ MISSING: hasTaintFlow=s16 MISSING: hasTaintFlow=s17 MISSING: hasTaintFlow=s18 MISSING: hasTaintFlow=s19 + .q(source("s17")).ljust(10, source("s18")) + .rjust(10, source("s19"))); // $ hasTaintFlow=s16 hasTaintFlow=s17 hasTaintFlow=s18 hasTaintFlow=s19 } From eb18c3ce24aca29fdd3649ddfa872ab6ec46e78f Mon Sep 17 00:00:00 2001 From: Napalys Date: Mon, 17 Mar 2025 18:36:23 +0100 Subject: [PATCH 15/23] Added test case for `tap`. --- .../ql/test/library-tests/TripleDot/underscore.string.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/javascript/ql/test/library-tests/TripleDot/underscore.string.js b/javascript/ql/test/library-tests/TripleDot/underscore.string.js index 66d7dd1b9e75..303d72764d8a 100644 --- a/javascript/ql/test/library-tests/TripleDot/underscore.string.js +++ b/javascript/ql/test/library-tests/TripleDot/underscore.string.js @@ -117,4 +117,8 @@ function chaining() { .strip().lstrip().rstrip().camelcase() .q(source("s17")).ljust(10, source("s18")) .rjust(10, source("s19"))); // $ hasTaintFlow=s16 hasTaintFlow=s17 hasTaintFlow=s18 hasTaintFlow=s19 + + sink(s(source("s20")).tap(function(value) { + return value + source("s21"); + }).value()); // $ MISSING: hasTaintFlow=s20 MISSING: hasTaintFlow=s21 } From d8e6d76b0e821d008a0f894f72e28750defb97cb Mon Sep 17 00:00:00 2001 From: Napalys Date: Mon, 17 Mar 2025 19:07:02 +0100 Subject: [PATCH 16/23] Added modeling for `tap` function. --- javascript/ql/lib/ext/underscore.string.model.yml | 3 +++ .../ql/test/library-tests/TripleDot/underscore.string.js | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/javascript/ql/lib/ext/underscore.string.model.yml b/javascript/ql/lib/ext/underscore.string.model.yml index 77c73d407f0c..e8ff73f5d714 100644 --- a/javascript/ql/lib/ext/underscore.string.model.yml +++ b/javascript/ql/lib/ext/underscore.string.model.yml @@ -7,6 +7,7 @@ extensions: - ["'underscore.string'.Wrapper", "'underscore.string'.Wrapper", "Member[slugify,capitalize,decapitalize,clean,cleanDiacritics,swapCase,escapeHTML,unescapeHTML,wrap,dedent,reverse,pred,succ,titleize,camelize,classify,underscored,dasherize,humanize,trim,ltrim,rtrim,truncate,sprintf,strRight,strRightBack,strLeft,strLeftBack,stripTags,unquote,value,strip,lstrip,rstrip,camelcase].ReturnValue"] - ["'underscore.string'.Wrapper", "'underscore.string'.Wrapper", "Member[insert,replaceAll,join,splice,prune,pad,lpad,rpad,repeat,surround,quote,q,rjust,ljust].ReturnValue"] - ["'underscore.string'.Wrapper", "'underscore.string'.Wrapper", "Member[toUpperCase,toLowerCase,replace,slice,substring,substr,concat].ReturnValue"] + - ["'underscore.string'.Wrapper", "'underscore.string'.Wrapper", "Member[tap].ReturnValue"] - addsTo: pack: codeql/javascript-all @@ -27,3 +28,5 @@ extensions: - ["'underscore.string'.Wrapper", "Member[splice]", "Argument[2]", "ReturnValue", "taint"] - ["'underscore.string'.Wrapper", "Member[join,concat]", "Argument[0..N-1]", "ReturnValue", "taint"] - ["'underscore.string'.Wrapper", "Member[toUpperCase,toLowerCase,replace,slice,substring,substr,split]", "Argument[this]", "ReturnValue", "taint"] + - ["'underscore.string'.Wrapper", "Member[tap]", "Argument[this]", "ReturnValue", "taint"] + - ["'underscore.string'.Wrapper", "Member[tap]", "Argument[0].ReturnValue", "ReturnValue", "taint"] diff --git a/javascript/ql/test/library-tests/TripleDot/underscore.string.js b/javascript/ql/test/library-tests/TripleDot/underscore.string.js index 303d72764d8a..61238fc52280 100644 --- a/javascript/ql/test/library-tests/TripleDot/underscore.string.js +++ b/javascript/ql/test/library-tests/TripleDot/underscore.string.js @@ -120,5 +120,5 @@ function chaining() { sink(s(source("s20")).tap(function(value) { return value + source("s21"); - }).value()); // $ MISSING: hasTaintFlow=s20 MISSING: hasTaintFlow=s21 + }).value()); // $ hasTaintFlow=s20 hasTaintFlow=s21 } From 2c7562d87599917227141514efb86f694bdbde5a Mon Sep 17 00:00:00 2001 From: Napalys Date: Mon, 17 Mar 2025 19:08:43 +0100 Subject: [PATCH 17/23] Removed `value` from modeling its return value as Wrapper class, since it return simple string. --- javascript/ql/lib/ext/underscore.string.model.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/lib/ext/underscore.string.model.yml b/javascript/ql/lib/ext/underscore.string.model.yml index e8ff73f5d714..2b955ae5a40b 100644 --- a/javascript/ql/lib/ext/underscore.string.model.yml +++ b/javascript/ql/lib/ext/underscore.string.model.yml @@ -4,7 +4,7 @@ extensions: extensible: typeModel data: - ["'underscore.string'.Wrapper", "'underscore.string'", "ReturnValue"] - - ["'underscore.string'.Wrapper", "'underscore.string'.Wrapper", "Member[slugify,capitalize,decapitalize,clean,cleanDiacritics,swapCase,escapeHTML,unescapeHTML,wrap,dedent,reverse,pred,succ,titleize,camelize,classify,underscored,dasherize,humanize,trim,ltrim,rtrim,truncate,sprintf,strRight,strRightBack,strLeft,strLeftBack,stripTags,unquote,value,strip,lstrip,rstrip,camelcase].ReturnValue"] + - ["'underscore.string'.Wrapper", "'underscore.string'.Wrapper", "Member[slugify,capitalize,decapitalize,clean,cleanDiacritics,swapCase,escapeHTML,unescapeHTML,wrap,dedent,reverse,pred,succ,titleize,camelize,classify,underscored,dasherize,humanize,trim,ltrim,rtrim,truncate,sprintf,strRight,strRightBack,strLeft,strLeftBack,stripTags,unquote,strip,lstrip,rstrip,camelcase].ReturnValue"] - ["'underscore.string'.Wrapper", "'underscore.string'.Wrapper", "Member[insert,replaceAll,join,splice,prune,pad,lpad,rpad,repeat,surround,quote,q,rjust,ljust].ReturnValue"] - ["'underscore.string'.Wrapper", "'underscore.string'.Wrapper", "Member[toUpperCase,toLowerCase,replace,slice,substring,substr,concat].ReturnValue"] - ["'underscore.string'.Wrapper", "'underscore.string'.Wrapper", "Member[tap].ReturnValue"] From 8b431dc0e7d7eb9f23476064c65319e6c8345871 Mon Sep 17 00:00:00 2001 From: Napalys Date: Mon, 17 Mar 2025 19:10:12 +0100 Subject: [PATCH 18/23] Added change note. --- .../ql/lib/change-notes/2025-03-17-underscore-string.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 javascript/ql/lib/change-notes/2025-03-17-underscore-string.md diff --git a/javascript/ql/lib/change-notes/2025-03-17-underscore-string.md b/javascript/ql/lib/change-notes/2025-03-17-underscore-string.md new file mode 100644 index 000000000000..c6bd442735ad --- /dev/null +++ b/javascript/ql/lib/change-notes/2025-03-17-underscore-string.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* Added support for the `underscore.string` package. From 922a07d01ef713bf9b30d1fc80b9cbcd9d96fd69 Mon Sep 17 00:00:00 2001 From: Napalys Date: Tue, 18 Mar 2025 11:35:33 +0100 Subject: [PATCH 19/23] Added `underscore.string` `clearsContent`. Co-authored-by: Asgerf --- javascript/ql/lib/javascript.qll | 1 + .../frameworks/UnderscoreDotString.qll | 25 +++++++++++++++++++ .../TripleDot/underscore.string.js | 4 +-- 3 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 javascript/ql/lib/semmle/javascript/frameworks/UnderscoreDotString.qll diff --git a/javascript/ql/lib/javascript.qll b/javascript/ql/lib/javascript.qll index 7bb2b7676105..cc4d15158b90 100644 --- a/javascript/ql/lib/javascript.qll +++ b/javascript/ql/lib/javascript.qll @@ -143,3 +143,4 @@ import semmle.javascript.linters.ESLint import semmle.javascript.linters.JSLint import semmle.javascript.linters.Linting import semmle.javascript.security.dataflow.RemoteFlowSources +import semmle.javascript.frameworks.UnderscoreDotString diff --git a/javascript/ql/lib/semmle/javascript/frameworks/UnderscoreDotString.qll b/javascript/ql/lib/semmle/javascript/frameworks/UnderscoreDotString.qll new file mode 100644 index 000000000000..9e30dc384040 --- /dev/null +++ b/javascript/ql/lib/semmle/javascript/frameworks/UnderscoreDotString.qll @@ -0,0 +1,25 @@ +/** + * Provides classes for modeling data flow behavior of the Underscore.string library (https://www.npmjs.com/package/underscore.string). + */ + +private import javascript +private import semmle.javascript.dataflow.internal.AdditionalFlowInternal + +/** + * Models data flow for the Underscore.string library. + */ +private class UnderscoreDotString extends AdditionalFlowInternal { + /** + * Holds if a call to an Underscore.string method clears array element content of the receiver. + */ + override predicate clearsContent(DataFlow::Node node, DataFlow::ContentSet contents) { + exists(DataFlow::CallNode call | + call = + ModelOutput::getATypeNode(["'underscore.string'.Wrapper", "'underscore.string'"]) + .getAMember() + .getACall() and + node = call.getReceiver().getPostUpdateNode() and + contents = DataFlow::ContentSet::arrayElement() + ) + } +} diff --git a/javascript/ql/test/library-tests/TripleDot/underscore.string.js b/javascript/ql/test/library-tests/TripleDot/underscore.string.js index 61238fc52280..d40477956246 100644 --- a/javascript/ql/test/library-tests/TripleDot/underscore.string.js +++ b/javascript/ql/test/library-tests/TripleDot/underscore.string.js @@ -11,7 +11,7 @@ function strToStr() { sink(s.unescapeHTML(source("s8"))); // $ hasTaintFlow=s8 sink(s.wrap(source("s9"), {})); // $ hasTaintFlow=s9 sink(s.dedent(source("s10"), " ")); // $ hasTaintFlow=s10 - sink(s.reverse(source("s11"))); // $ hasTaintFlow=s11 SPURIOUS: hasTaintFlow=s8 + sink(s.reverse(source("s11"))); // $ hasTaintFlow=s11 sink(s.pred(source("s12"))); // $ hasTaintFlow=s12 sink(s.succ(source("s13"))); // $ hasTaintFlow=s13 sink(s.titleize(source("s14"))); // $ hasTaintFlow=s14 @@ -60,7 +60,7 @@ function multiSource() { sink(s.join(",", source("s5"), "str")); // $ hasTaintFlow=s5 sink(s.join(",", "str", source("s6"))); // $ hasTaintFlow=s6 - sink(s.splice(source("s7"), 1, 2, "str")); // $ hasTaintFlow=s7 SPURIOUS: hasTaintFlow=s8 + sink(s.splice(source("s7"), 1, 2, "str")); // $ hasTaintFlow=s7 sink(s.splice("str", 1, 2, source("s8"))); // $ hasTaintFlow=s8 sink(s.prune(source("s9"), 1, "additional")); // $ hasTaintFlow=s9 From 752f02f04d1b35e8cb102c3db1ecb31af1ba1089 Mon Sep 17 00:00:00 2001 From: Napalys Date: Thu, 20 Mar 2025 12:18:28 +0100 Subject: [PATCH 20/23] Fixed `map` modeling and added test cases. --- javascript/ql/lib/ext/underscore.string.model.yml | 4 +++- .../ql/test/library-tests/TripleDot/underscore.string.js | 5 +++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/javascript/ql/lib/ext/underscore.string.model.yml b/javascript/ql/lib/ext/underscore.string.model.yml index 2b955ae5a40b..a9e720d6f909 100644 --- a/javascript/ql/lib/ext/underscore.string.model.yml +++ b/javascript/ql/lib/ext/underscore.string.model.yml @@ -13,7 +13,7 @@ extensions: pack: codeql/javascript-all extensible: summaryModel data: - - ["'underscore.string'", "Member[slugify,capitalize,decapitalize,clean,cleanDiacritics,swapCase,escapeHTML,unescapeHTML,wrap,dedent,reverse,pred,succ,titleize,camelize,classify,underscored,dasherize,humanize,trim,ltrim,rtrim,truncate,sprintf,strRight,strRightBack,strLeft,strLeftBack,stripTags,unquote,map,strip,lstrip,rstrip,camelcase]", "Argument[0]", "ReturnValue", "taint"] + - ["'underscore.string'", "Member[slugify,capitalize,decapitalize,clean,cleanDiacritics,swapCase,escapeHTML,unescapeHTML,wrap,dedent,reverse,pred,succ,titleize,camelize,classify,underscored,dasherize,humanize,trim,ltrim,rtrim,truncate,sprintf,strRight,strRightBack,strLeft,strLeftBack,stripTags,unquote,strip,lstrip,rstrip,camelcase]", "Argument[0]", "ReturnValue", "taint"] - ["'underscore.string'", "Member[chop,chars,words,lines]", "Argument[0]", "ReturnValue", "taint"] - ["'underscore.string'", "Member[toSentence,toSentenceSerial]", "Argument[0].ArrayElement", "ReturnValue", "taint"] - ["'underscore.string'", "Member[insert,replaceAll,splice,prune,pad,lpad,rpad,repeat,rjust,ljust]", "Argument[0,2]", "ReturnValue", "taint"] @@ -30,3 +30,5 @@ extensions: - ["'underscore.string'.Wrapper", "Member[toUpperCase,toLowerCase,replace,slice,substring,substr,split]", "Argument[this]", "ReturnValue", "taint"] - ["'underscore.string'.Wrapper", "Member[tap]", "Argument[this]", "ReturnValue", "taint"] - ["'underscore.string'.Wrapper", "Member[tap]", "Argument[0].ReturnValue", "ReturnValue", "taint"] + - ["'underscore.string'", "Member[map]", "Argument[0]", "Argument[1].Parameter[0]", "taint"] + - ["'underscore.string'", "Member[map]", "Argument[1].ReturnValue", "ReturnValue", "taint"] diff --git a/javascript/ql/test/library-tests/TripleDot/underscore.string.js b/javascript/ql/test/library-tests/TripleDot/underscore.string.js index d40477956246..c7435ad97572 100644 --- a/javascript/ql/test/library-tests/TripleDot/underscore.string.js +++ b/javascript/ql/test/library-tests/TripleDot/underscore.string.js @@ -122,3 +122,8 @@ function chaining() { return value + source("s21"); }).value()); // $ hasTaintFlow=s20 hasTaintFlow=s21 } + +function mapTests(){ + sink(s.map(source("s1"), (x) => {return x + source("s2");})); // $ hasTaintFlow=s1 hasTaintFlow=s2 + s.map(source("s1"), (x) => { sink(x); return x;}); // $ hasTaintFlow=s1 +} From f4ca2dc1f30a445a9cc136b62b61ab16b35f309e Mon Sep 17 00:00:00 2001 From: Napalys Date: Thu, 20 Mar 2025 12:24:49 +0100 Subject: [PATCH 21/23] Restricted taint to array elements. --- javascript/ql/lib/ext/underscore.string.model.yml | 2 +- .../ql/test/library-tests/TripleDot/underscore.string.js | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/javascript/ql/lib/ext/underscore.string.model.yml b/javascript/ql/lib/ext/underscore.string.model.yml index a9e720d6f909..5f9dcf249460 100644 --- a/javascript/ql/lib/ext/underscore.string.model.yml +++ b/javascript/ql/lib/ext/underscore.string.model.yml @@ -14,7 +14,7 @@ extensions: extensible: summaryModel data: - ["'underscore.string'", "Member[slugify,capitalize,decapitalize,clean,cleanDiacritics,swapCase,escapeHTML,unescapeHTML,wrap,dedent,reverse,pred,succ,titleize,camelize,classify,underscored,dasherize,humanize,trim,ltrim,rtrim,truncate,sprintf,strRight,strRightBack,strLeft,strLeftBack,stripTags,unquote,strip,lstrip,rstrip,camelcase]", "Argument[0]", "ReturnValue", "taint"] - - ["'underscore.string'", "Member[chop,chars,words,lines]", "Argument[0]", "ReturnValue", "taint"] + - ["'underscore.string'", "Member[chop,chars,words,lines]", "Argument[0]", "ReturnValue.ArrayElement", "taint"] - ["'underscore.string'", "Member[toSentence,toSentenceSerial]", "Argument[0].ArrayElement", "ReturnValue", "taint"] - ["'underscore.string'", "Member[insert,replaceAll,splice,prune,pad,lpad,rpad,repeat,rjust,ljust]", "Argument[0,2]", "ReturnValue", "taint"] - ["'underscore.string'", "Member[splice]", "Argument[0,3]", "ReturnValue", "taint"] diff --git a/javascript/ql/test/library-tests/TripleDot/underscore.string.js b/javascript/ql/test/library-tests/TripleDot/underscore.string.js index c7435ad97572..8fd919e74097 100644 --- a/javascript/ql/test/library-tests/TripleDot/underscore.string.js +++ b/javascript/ql/test/library-tests/TripleDot/underscore.string.js @@ -39,10 +39,11 @@ function strToStr() { } function strToArray() { - sink(s.chop(source("s1"), 3)[0]); // $ hasTaintFlow=s1 - sink(s.chars(source("s2")[0])); // $ hasTaintFlow=s2 - sink(s.words(source("s3")[0])); // $ hasTaintFlow=s3 - sink(s.lines(source("s7")[0])); // $ hasTaintFlow=s7 + sink(s.chop(source("s1"), 3)); // $ MISSING: hasTaintFlow=s1 + sink(s.chars(source("s2")[0])); // $ MISSING: hasTaintFlow=s2 + sink(s.words(source("s3")[0])); // $ MISSING: hasTaintFlow=s3 + sink(s.lines(source("s7")[0])); // $ MISSING: hasTaintFlow=s7 + sink(s.chop(source("s1"), 3).length); } function arrayToStr() { From ca53e97de4358bed4e6bd21dcd535096d01ab1de Mon Sep 17 00:00:00 2001 From: Napalys Date: Thu, 20 Mar 2025 12:37:06 +0100 Subject: [PATCH 22/23] Adressed comments. --- javascript/ql/lib/ext/underscore.string.model.yml | 5 +++-- .../lib/semmle/javascript/frameworks/UnderscoreDotString.qll | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/javascript/ql/lib/ext/underscore.string.model.yml b/javascript/ql/lib/ext/underscore.string.model.yml index 5f9dcf249460..d1330279f74b 100644 --- a/javascript/ql/lib/ext/underscore.string.model.yml +++ b/javascript/ql/lib/ext/underscore.string.model.yml @@ -18,7 +18,7 @@ extensions: - ["'underscore.string'", "Member[toSentence,toSentenceSerial]", "Argument[0].ArrayElement", "ReturnValue", "taint"] - ["'underscore.string'", "Member[insert,replaceAll,splice,prune,pad,lpad,rpad,repeat,rjust,ljust]", "Argument[0,2]", "ReturnValue", "taint"] - ["'underscore.string'", "Member[splice]", "Argument[0,3]", "ReturnValue", "taint"] - - ["'underscore.string'", "Member[join]", "Argument[0..N-1]", "ReturnValue", "taint"] + - ["'underscore.string'", "Member[join]", "Argument[0..]", "ReturnValue", "taint"] - ["'underscore.string'", "Member[surround,quote,q]", "Argument[0,1]", "ReturnValue", "taint"] - ["'underscore.string'", "", "Argument[0]", "ReturnValue", "taint"] - ["'underscore.string'.Wrapper", "Member[slugify,capitalize,decapitalize,clean,cleanDiacritics,swapCase,escapeHTML,unescapeHTML,wrap,dedent,reverse,pred,succ,titleize,camelize,classify,underscored,dasherize,humanize,trim,ltrim,rtrim,truncate,sprintf,strRight,strRightBack,strLeft,strLeftBack,stripTags,unquote,value,strip,lstrip,rstrip,camelcase]", "Argument[this]", "ReturnValue", "taint"] @@ -26,9 +26,10 @@ extensions: - ["'underscore.string'.Wrapper", "Member[insert,replaceAll,prune,pad,lpad,rpad,repeat,rjust,ljust]", "Argument[1]", "ReturnValue", "taint"] - ["'underscore.string'.Wrapper", "Member[surround,quote,q]", "Argument[0]", "ReturnValue", "taint"] - ["'underscore.string'.Wrapper", "Member[splice]", "Argument[2]", "ReturnValue", "taint"] - - ["'underscore.string'.Wrapper", "Member[join,concat]", "Argument[0..N-1]", "ReturnValue", "taint"] + - ["'underscore.string'.Wrapper", "Member[join,concat]", "Argument[0..]", "ReturnValue", "taint"] - ["'underscore.string'.Wrapper", "Member[toUpperCase,toLowerCase,replace,slice,substring,substr,split]", "Argument[this]", "ReturnValue", "taint"] - ["'underscore.string'.Wrapper", "Member[tap]", "Argument[this]", "ReturnValue", "taint"] - ["'underscore.string'.Wrapper", "Member[tap]", "Argument[0].ReturnValue", "ReturnValue", "taint"] + - ["'underscore.string'.Wrapper", "Member[tap]", "Argument[this]", "Argument[0].Parameter[1]", "taint"] - ["'underscore.string'", "Member[map]", "Argument[0]", "Argument[1].Parameter[0]", "taint"] - ["'underscore.string'", "Member[map]", "Argument[1].ReturnValue", "ReturnValue", "taint"] diff --git a/javascript/ql/lib/semmle/javascript/frameworks/UnderscoreDotString.qll b/javascript/ql/lib/semmle/javascript/frameworks/UnderscoreDotString.qll index 9e30dc384040..abb51b978bc0 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/UnderscoreDotString.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/UnderscoreDotString.qll @@ -10,7 +10,8 @@ private import semmle.javascript.dataflow.internal.AdditionalFlowInternal */ private class UnderscoreDotString extends AdditionalFlowInternal { /** - * Holds if a call to an Underscore.string method clears array element content of the receiver. + * Some of the methods in `underscore.string` have the same name as methods from `Array.prototype`. + * This prevents methods like `splice` from propagating into Argument[this].ArrayElement. */ override predicate clearsContent(DataFlow::Node node, DataFlow::ContentSet contents) { exists(DataFlow::CallNode call | From 9e787555df5084997eb7b96dfe469aacbd6e6964 Mon Sep 17 00:00:00 2001 From: Napalys Date: Thu, 20 Mar 2025 13:25:36 +0100 Subject: [PATCH 23/23] Fixed typo in the test cases. --- .../ql/test/library-tests/TripleDot/underscore.string.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/javascript/ql/test/library-tests/TripleDot/underscore.string.js b/javascript/ql/test/library-tests/TripleDot/underscore.string.js index 8fd919e74097..07f186343ce2 100644 --- a/javascript/ql/test/library-tests/TripleDot/underscore.string.js +++ b/javascript/ql/test/library-tests/TripleDot/underscore.string.js @@ -40,9 +40,9 @@ function strToStr() { function strToArray() { sink(s.chop(source("s1"), 3)); // $ MISSING: hasTaintFlow=s1 - sink(s.chars(source("s2")[0])); // $ MISSING: hasTaintFlow=s2 - sink(s.words(source("s3")[0])); // $ MISSING: hasTaintFlow=s3 - sink(s.lines(source("s7")[0])); // $ MISSING: hasTaintFlow=s7 + sink(s.chars(source("s2"))[0]); // $ hasTaintFlow=s2 + sink(s.words(source("s3"))[0]); // $ hasTaintFlow=s3 + sink(s.lines(source("s7"))[0]); // $ hasTaintFlow=s7 sink(s.chop(source("s1"), 3).length); }