Skip to content

Commit 286c655

Browse files
Jami CogswellJami Cogswell
authored andcommitted
Java: add class for Stapler web methods that are not default-protected from CSRF
1 parent 0f39011 commit 286c655

File tree

2 files changed

+53
-0
lines changed

2 files changed

+53
-0
lines changed

java/ql/lib/semmle/code/java/frameworks/stapler/Stapler.qll

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,3 +122,40 @@ private class PostConstructDataBoundMethod extends Method {
122122
this.getAnAnnotation() instanceof PostConstructAnnotation
123123
}
124124
}
125+
126+
/**
127+
* A method intended for Stapler request routing.
128+
*
129+
* From: https://www.jenkins.io/doc/developer/handling-requests/actions/
130+
* Web methods need to provide some indication that they are intended for Stapler routing:
131+
* - Any applicable annotation recognized by Stapler, e.g., @RequirePOST.
132+
* - Any inferable parameter type, e.g., StaplerRequest.
133+
* - Any applicable parameter annotation, recognized by Stapler, e.g., @AncestorInPath.
134+
* - Any declared exception type implementing HttpResponse, e.g., HttpResponseException.
135+
* - A return type implementing HttpResponse.
136+
*/
137+
class StaplerWebMethod extends Method {
138+
StaplerWebMethod() {
139+
// Any applicable annotation recognized by Stapler, e.g., @RequirePOST.
140+
this.hasAnnotation("org.kohsuke.stapler", "WebMethod")
141+
or
142+
this.hasAnnotation("org.kohsuke.stapler.interceptor", ["RequirePOST", "RespondSuccess"])
143+
or
144+
this.hasAnnotation("org.kohsuke.stapler.verb", ["DELETE", "GET", "POST", "PUT"])
145+
or
146+
// Any inferable parameter type, e.g., StaplerRequest.
147+
this.getAParamType()
148+
.(RefType)
149+
.hasQualifiedName("org.kohsuke.stapler", ["StaplerRequest", "StaplerRequest2"])
150+
or
151+
// Any applicable parameter annotation, recognized by Stapler, e.g., @AncestorInPath
152+
this.getAParameter()
153+
.hasAnnotation("org.kohsuke.stapler", ["AncestorInPath", "QueryParameter", "Header"])
154+
or
155+
// A return type implementing HttpResponse
156+
this.getReturnType().(RefType).getASourceSupertype*() instanceof HttpResponse
157+
or
158+
// Any declared exception type implementing HttpResponse, e.g., HttpResponseException
159+
this.getAThrownExceptionType().getASourceSupertype*() instanceof HttpResponse
160+
}
161+
}

java/ql/lib/semmle/code/java/security/CsrfUnprotectedRequestTypeQuery.qll

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import java
44
private import semmle.code.java.frameworks.spring.SpringController
5+
private import semmle.code.java.frameworks.stapler.Stapler
56
private import semmle.code.java.frameworks.MyBatis
67
private import semmle.code.java.frameworks.Jdbc
78
private import semmle.code.java.dataflow.ExternalFlow
@@ -33,6 +34,21 @@ private class SpringCsrfUnprotectedMethod extends CsrfUnprotectedMethod instance
3334
}
3435
}
3536

37+
/**
38+
* A Stapler web method that is not protected from CSRF by default.
39+
*
40+
* https://www.jenkins.io/doc/developer/security/form-validation/#protecting-from-csrf
41+
*/
42+
private class StaplerCsrfUnprotectedMethod extends CsrfUnprotectedMethod instanceof StaplerWebMethod
43+
{
44+
StaplerCsrfUnprotectedMethod() {
45+
not (
46+
this.hasAnnotation("org.kohsuke.stapler.interceptor", "RequirePOST") or
47+
this.hasAnnotation("org.kohsuke.stapler.verb", "POST")
48+
)
49+
}
50+
}
51+
3652
/** A method that updates a database. */
3753
abstract class DatabaseUpdateMethod extends Method { }
3854

0 commit comments

Comments
 (0)