Skip to content

Commit d940085

Browse files
committed
Spring HTTP: inherit produced content-types from surrounding class
1 parent bdd135d commit d940085

File tree

2 files changed

+22
-6
lines changed

2 files changed

+22
-6
lines changed

java/ql/lib/semmle/code/java/frameworks/spring/SpringController.qll

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -100,28 +100,44 @@ class SpringResponseBodyAnnotationType extends AnnotationType {
100100
}
101101
}
102102

103+
private class SpringRequestMappingAnnotation extends Annotation {
104+
SpringRequestMappingAnnotation() { this.getType() instanceof SpringRequestMappingAnnotationType }
105+
}
106+
107+
private Expr getProducesExpr(RefType rt) {
108+
result = rt.getAnAnnotation().(SpringRequestMappingAnnotation).getValue("produces")
109+
or
110+
rt.getAnAnnotation().(SpringRequestMappingAnnotation).getValue("produces").(ArrayInit).getSize() =
111+
0 and
112+
result = getProducesExpr(rt.getASupertype())
113+
}
114+
103115
/**
104116
* A method on a Spring controller that is executed in response to a web request.
105117
*/
106118
class SpringRequestMappingMethod extends SpringControllerMethod {
107-
Annotation requestMappingAnnotation;
119+
SpringRequestMappingAnnotation requestMappingAnnotation;
108120

109121
SpringRequestMappingMethod() {
110122
// Any method that declares the @RequestMapping annotation, or overrides a method that declares
111123
// the annotation. We have to do this explicit check because the @RequestMapping annotation is
112124
// not declared with @Inherited.
113125
exists(Method superMethod |
114126
this.overrides*(superMethod) and
115-
requestMappingAnnotation = superMethod.getAnAnnotation() and
116-
requestMappingAnnotation.getType() instanceof SpringRequestMappingAnnotationType
127+
requestMappingAnnotation = superMethod.getAnAnnotation()
117128
)
118129
}
119130

120131
/** Gets a request mapping parameter. */
121132
SpringRequestMappingParameter getARequestParameter() { result = getAParameter() }
122133

123134
/** Gets the "produces" @RequestMapping annotation value, if present. */
124-
Expr getProducesExpr() { result = requestMappingAnnotation.getValue("produces") }
135+
Expr getProducesExpr() {
136+
result = requestMappingAnnotation.getValue("produces")
137+
or
138+
requestMappingAnnotation.getValue("produces").(ArrayInit).getSize() = 0 and
139+
result = getProducesExpr(this.getDeclaringType())
140+
}
125141

126142
/** Gets the "produces" @RequestMapping annotation value, if present. */
127143
Expr getAProducesExpr() {

java/ql/test/query-tests/security/CWE-079/semmle/tests/SpringXSS.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,12 +105,12 @@ public static ResponseEntity<String> methodContentTypeMaybeSafeStringLiterals(St
105105
private static class ClassContentTypeSafe {
106106
@GetMapping(value = "/abc")
107107
public ResponseEntity<String> test(String userControlled) {
108-
return ResponseEntity.ok(userControlled); // $SPURIOUS: xss
108+
return ResponseEntity.ok(userControlled);
109109
}
110110

111111
@GetMapping(value = "/abc")
112112
public String testDirectReturn(String userControlled) {
113-
return userControlled; // $SPURIOUS: xss
113+
return userControlled;
114114
}
115115

116116
@GetMapping(value = "/xyz", produces = {"text/html"})

0 commit comments

Comments
 (0)