@@ -48,52 +48,70 @@ private class LineBreaksLogInjectionSanitizer extends LogInjectionSanitizer {
4848 }
4949}
5050
51- private predicate stringMethodCall (
52- MethodCall mc , CompileTimeConstantExpr arg0 , CompileTimeConstantExpr arg1
53- ) {
54- mc .getMethod ( ) .getDeclaringType ( ) instanceof TypeString and
55- arg0 = mc .getArgument ( 0 ) and
56- arg1 = mc .getArgument ( 1 )
51+ bindingset [ match]
52+ pragma [ inline_late]
53+ private predicate stringOrCharValueMatches ( CompileTimeConstantExpr const , string match ) {
54+ const .getStringOrCharValue ( ) .matches ( match )
5755}
5856
59- private predicate stringMethodArgument ( CompileTimeConstantExpr arg ) {
60- stringMethodCall ( _ , arg , _ ) or stringMethodCall ( _ , _ , arg )
57+ private predicate containsLineBreak ( CompileTimeConstantExpr const ) {
58+ stringOrCharValueMatches ( const , [ "%\n%" , "%\r%" ] )
6159}
6260
63- bindingset [ match]
64- pragma [ inline_late]
65- private predicate stringMethodArgumentValueMatches ( CompileTimeConstantExpr const , string match ) {
66- stringMethodArgument ( const ) and
67- const .getStringValue ( ) .matches ( match )
61+ private predicate containsBothLineBreaks ( CompileTimeConstantExpr const ) {
62+ stringOrCharValueMatches ( const , "%\n%" ) and stringOrCharValueMatches ( const , "%\r%" )
63+ }
64+
65+ private predicate regexRemovesLineBreaks ( CompileTimeConstantExpr target ) {
66+ // Replace anything not in an allow list
67+ target .getStringValue ( ) .matches ( "[^%]" ) and
68+ not stringOrCharValueMatches ( target , "%" + [ "\n" , "\r" , "\\n" , "\\r" , "\\R" ] + "%" )
69+ or
70+ // Replace line breaks
71+ target .getStringValue ( ) = [ "\n" , "\r" , "\\n" , "\\r" , "\\R" ]
72+ }
73+
74+ private predicate replacementRemovesLineBreaks (
75+ StringReplacement replacement , CompileTimeConstantExpr target
76+ ) {
77+ target = replacement .getMatchExpression ( ) and
78+ (
79+ replacement .matchExpressionIsCharacterSet ( ) and containsBothLineBreaks ( target )
80+ or
81+ replacement .matchExpressionIsRegex ( ) and regexRemovesLineBreaks ( target )
82+ or
83+ not replacement .matchExpressionIsCharacterSet ( ) and
84+ not replacement .matchExpressionIsRegex ( ) and
85+ target .getStringOrCharValue ( ) = [ "\n" , "\r" ]
86+ )
87+ }
88+
89+ private predicate removalRemovesLineBreaks ( StringRemoval removal , CompileTimeConstantExpr target ) {
90+ target = removal .getMatchExpression ( ) and
91+ (
92+ removal .matchExpressionIsCharacterSet ( ) and containsBothLineBreaks ( target )
93+ or
94+ removal .matchExpressionIsRegex ( ) and regexRemovesLineBreaks ( target )
95+ or
96+ not removal .matchExpressionIsCharacterSet ( ) and
97+ not removal .matchExpressionIsRegex ( ) and
98+ target .getStringOrCharValue ( ) = [ "\n" , "\r" ]
99+ )
68100}
69101
70102/**
71103 * Holds if `e` is sanitized against log injection attacks by removing line
72104 * breaks from it.
73105 */
74106private predicate logInjectionSanitizer ( Expr e ) {
75- exists ( MethodCall mc , CompileTimeConstantExpr target , CompileTimeConstantExpr replacement |
76- e = mc and
77- stringMethodCall ( mc , target , replacement ) and
78- not stringMethodArgumentValueMatches ( replacement , [ "%\n%" , "%\r%" ] )
79- |
80- mc .getMethod ( ) .hasName ( "replace" ) and
81- not replacement .getIntValue ( ) = [ 10 , 13 ] and
82- (
83- target .getIntValue ( ) = [ 10 , 13 ] or // 10 == '\n', 13 == '\r'
84- target .getStringValue ( ) = [ "\n" , "\r" ]
85- )
86- or
87- mc .getMethod ( ) .hasName ( "replaceAll" ) and
88- (
89- // Replace anything not in an allow list
90- target .getStringValue ( ) .matches ( "[^%]" ) and
91- not stringMethodArgumentValueMatches ( target , "%" + [ "\n" , "\r" , "\\n" , "\\r" , "\\R" ] + "%" )
92- or
93- // Replace line breaks
94- target .getStringValue ( ) = [ "\n" , "\r" , "\\n" , "\\r" , "\\R" ]
95- )
107+ replacementRemovesLineBreaks ( e , _) and
108+ exists ( CompileTimeConstantExpr replacement |
109+ replacement = e .( StringReplacement ) .getReplacement ( ) and
110+ exists ( replacement .getStringOrCharValue ( ) ) and
111+ not containsLineBreak ( replacement )
96112 )
113+ or
114+ removalRemovesLineBreaks ( e , _)
97115}
98116
99117/**
0 commit comments