@@ -33,7 +33,23 @@ predicate isSensitiveCookieNameExpr(Expr expr) {
33
33
34
34
/** Holds if a string is concatenated with the `HttpOnly` flag. */
35
35
predicate hasHttpOnlyExpr ( Expr expr ) {
36
- expr .( CompileTimeConstantExpr ) .getStringValue ( ) .toLowerCase ( ) .matches ( "%httponly%" ) or
36
+ (
37
+ expr .( CompileTimeConstantExpr ) .getStringValue ( ) .toLowerCase ( ) .matches ( "%httponly%" )
38
+ or
39
+ exists (
40
+ StaticMethodAccess ma // String.format("%s=%s;HttpOnly", "sessionkey", sessionKey)
41
+ |
42
+ ma .getType ( ) .getName ( ) = "String" and
43
+ ma .getMethod ( ) .getName ( ) = "format" and
44
+ ma .getArgument ( 0 )
45
+ .( CompileTimeConstantExpr )
46
+ .getStringValue ( )
47
+ .toLowerCase ( )
48
+ .matches ( "%httponly%" ) and
49
+ expr = ma
50
+ )
51
+ )
52
+ or
37
53
hasHttpOnlyExpr ( expr .( AddExpr ) .getAnOperand ( ) )
38
54
}
39
55
@@ -56,6 +72,40 @@ class CookieClass extends RefType {
56
72
}
57
73
}
58
74
75
+ /** Holds if the `Expr` expr is evaluated to boolean true. */
76
+ predicate isBooleanTrue ( Expr expr ) {
77
+ expr .( CompileTimeConstantExpr ) .getBooleanValue ( ) = true or
78
+ expr .( VarAccess ) .getVariable ( ) .getAnAssignedValue ( ) .( CompileTimeConstantExpr ) .getBooleanValue ( ) =
79
+ true
80
+ }
81
+
82
+ /** Holds if the method or a wrapper method sets the `HttpOnly` flag. */
83
+ predicate setHttpOnlyInCookie ( MethodAccess ma ) {
84
+ ma .getMethod ( ) .getName ( ) = "setHttpOnly" and
85
+ (
86
+ isBooleanTrue ( ma .getArgument ( 0 ) ) // boolean literal true
87
+ or
88
+ exists (
89
+ MethodAccess mpa , int i // runtime assignment of boolean value true
90
+ |
91
+ TaintTracking:: localTaint ( DataFlow:: parameterNode ( mpa .getMethod ( ) .getParameter ( i ) ) ,
92
+ DataFlow:: exprNode ( ma .getArgument ( 0 ) ) ) and
93
+ isBooleanTrue ( mpa .getArgument ( i ) )
94
+ )
95
+ )
96
+ or
97
+ exists ( MethodAccess mca |
98
+ ma .getMethod ( ) .calls ( mca .getMethod ( ) ) and
99
+ setHttpOnlyInCookie ( mca )
100
+ )
101
+ }
102
+
103
+ /** Holds if the method or a wrapper method removes a cookie. */
104
+ predicate removeCookie ( MethodAccess ma ) {
105
+ ma .getMethod ( ) .getName ( ) = "setMaxAge" and
106
+ ma .getArgument ( 0 ) .( IntegerLiteral ) .getIntValue ( ) = 0
107
+ }
108
+
59
109
/** Sensitive cookie name used in a `Cookie` constructor or a `Set-Cookie` call. */
60
110
class SensitiveCookieNameExpr extends Expr {
61
111
SensitiveCookieNameExpr ( ) { isSensitiveCookieNameExpr ( this ) }
@@ -69,11 +119,16 @@ class CookieResponseSink extends DataFlow::ExprNode {
69
119
ma .getMethod ( ) instanceof ResponseAddCookieMethod and
70
120
this .getExpr ( ) = ma .getArgument ( 0 ) and
71
121
not exists (
72
- MethodAccess ma2 // cookie.setHttpOnly(true)
122
+ MethodAccess ma2 // a method or wrapper method that invokes cookie.setHttpOnly(true)
73
123
|
74
- ma2 .getMethod ( ) .getName ( ) = "setHttpOnly" and
75
- ma2 .getArgument ( 0 ) .( BooleanLiteral ) .getBooleanValue ( ) = true and
76
- DataFlow:: localExprFlow ( ma2 .getQualifier ( ) , this .getExpr ( ) )
124
+ (
125
+ setHttpOnlyInCookie ( ma2 ) or
126
+ removeCookie ( ma2 )
127
+ ) and
128
+ (
129
+ DataFlow:: localExprFlow ( ma2 .getQualifier ( ) , this .getExpr ( ) ) or
130
+ DataFlow:: localExprFlow ( ma2 , this .getExpr ( ) )
131
+ )
77
132
)
78
133
or
79
134
ma instanceof SetCookieMethodAccess and
@@ -92,13 +147,15 @@ class CookieResponseSink extends DataFlow::ExprNode {
92
147
predicate setHttpOnlyInNewCookie ( ClassInstanceExpr cie ) {
93
148
cie .getConstructedType ( ) .hasQualifiedName ( [ "javax.ws.rs.core" , "jakarta.ws.rs.core" ] , "NewCookie" ) and
94
149
(
95
- cie .getNumArgument ( ) = 6 and cie .getArgument ( 5 ) .( BooleanLiteral ) .getBooleanValue ( ) = true // NewCookie(Cookie cookie, String comment, int maxAge, Date expiry, boolean secure, boolean httpOnly)
150
+ cie .getNumArgument ( ) = 6 and
151
+ isBooleanTrue ( cie .getArgument ( 5 ) ) // NewCookie(Cookie cookie, String comment, int maxAge, Date expiry, boolean secure, boolean httpOnly)
96
152
or
97
153
cie .getNumArgument ( ) = 8 and
98
154
cie .getArgument ( 6 ) .getType ( ) instanceof BooleanType and
99
- cie .getArgument ( 7 ) . ( BooleanLiteral ) . getBooleanValue ( ) = true // NewCookie(String name, String value, String path, String domain, String comment, int maxAge, boolean secure, boolean httpOnly)
155
+ isBooleanTrue ( cie .getArgument ( 7 ) ) // NewCookie(String name, String value, String path, String domain, String comment, int maxAge, boolean secure, boolean httpOnly)
100
156
or
101
- cie .getNumArgument ( ) = 10 and cie .getArgument ( 9 ) .( BooleanLiteral ) .getBooleanValue ( ) = true // NewCookie(String name, String value, String path, String domain, int version, String comment, int maxAge, Date expiry, boolean secure, boolean httpOnly)
157
+ cie .getNumArgument ( ) = 10 and
158
+ isBooleanTrue ( cie .getArgument ( 9 ) ) // NewCookie(String name, String value, String path, String domain, int version, String comment, int maxAge, Date expiry, boolean secure, boolean httpOnly)
102
159
)
103
160
}
104
161
0 commit comments