@@ -126,15 +126,22 @@ predicate isDelimiterUnwrapper(
126126}
127127
128128/*
129- * Holds if `repl` is a standalone use of `String.prototype.replace` to remove a single newline.
129+ * Holds if `repl` is a standalone use of `String.prototype.replace` to remove a single newline,
130+ * dollar or percent character.
131+ *
132+ * This is often done on inputs that are known to only contain a single instance of the character,
133+ * such as output from a shell command that is known to end with a single newline, or strings
134+ * like "$1.20" or "50%".
130135 */
131136
132- predicate removesTrailingNewLine ( StringReplaceCall repl ) {
137+ predicate whitelistedRemoval ( StringReplaceCall repl ) {
133138 not repl .isGlobal ( ) and
134- repl .replaces ( "\n" , "" ) and
135- not exists ( StringReplaceCall other |
136- repl .getAMethodCall ( ) = other or
137- other .getAMethodCall ( ) = repl
139+ exists ( string s | s = "\n" or s = "%" or s = "$" |
140+ repl .replaces ( s , "" ) and
141+ not exists ( StringReplaceCall other |
142+ repl .getAMethodCall ( ) = other or
143+ other .getAMethodCall ( ) = repl
144+ )
138145 )
139146}
140147
@@ -165,8 +172,8 @@ where
165172 // dont' flag unwrapper
166173 not isDelimiterUnwrapper ( repl , _) and
167174 not isDelimiterUnwrapper ( _, repl ) and
168- // dont' flag the removal of trailing newlines
169- not removesTrailingNewLine ( repl )
175+ // don't flag replacements of certain characters with whitespace
176+ not whitelistedRemoval ( repl )
170177 or
171178 exists ( DataFlow:: RegExpLiteralNode rel |
172179 isBackslashEscape ( repl , rel ) and
0 commit comments