mirror of
https://github.com/github/codeql.git
synced 2026-02-28 12:53:49 +01:00
Add @Pattern as RegexExecution => SSRF sanitizer
This commit is contained in:
@@ -8,6 +8,7 @@ module;
|
||||
|
||||
import java
|
||||
private import semmle.code.java.dataflow.DataFlow
|
||||
private import semmle.code.java.frameworks.JavaxAnnotations
|
||||
|
||||
/**
|
||||
* A data-flow node that executes a regular expression.
|
||||
|
||||
@@ -163,3 +163,38 @@ class WebServiceAnnotation extends Annotation {
|
||||
class WebServiceRefAnnotation extends Annotation {
|
||||
WebServiceRefAnnotation() { this.getType().hasQualifiedName("javax.xml.ws", "WebServiceRef") }
|
||||
}
|
||||
|
||||
/*
|
||||
* Annotations in the package `javax.validation.constraints`.
|
||||
*/
|
||||
|
||||
/**
|
||||
* A `@javax.validation.constraints.Pattern` annotation.
|
||||
*/
|
||||
class PatternAnnotation extends Annotation, RegexExecutionExpr::Range {
|
||||
PatternAnnotation() {
|
||||
this.getType()
|
||||
.hasQualifiedName(["javax.validation.constraints", "jakarta.validation.constraints"],
|
||||
"Pattern")
|
||||
}
|
||||
|
||||
override Expr getRegex() { result = this.getValue("regexp") }
|
||||
|
||||
override Expr getString() {
|
||||
// Annotation on field accessed by direct read - value of field will match regexp
|
||||
result = this.getAnnotatedElement().(Field).getAnAccess()
|
||||
or
|
||||
// Annotation on field accessed by getter - value of field will match regexp
|
||||
result.(MethodCall).getMethod().(GetterMethod).getField() = this.getAnnotatedElement()
|
||||
or
|
||||
// Annotation on parameter - value of parameter will match regexp
|
||||
result = this.getAnnotatedElement().(Parameter).getAnAccess().(VarRead)
|
||||
or
|
||||
// Annotation on method - return value of method will match regexp
|
||||
result.(Call).getCallee() = this.getAnnotatedElement()
|
||||
// TODO - we could also consider the case where the annotation is on a type
|
||||
// but this harder to model and not very common.
|
||||
}
|
||||
|
||||
override string getName() { result = "@javax.validation.constraints.Pattern annotation" }
|
||||
}
|
||||
|
||||
@@ -41,17 +41,11 @@ class SimpleTypeSanitizer extends DataFlow::Node {
|
||||
* make the type recursive. Otherwise use `RegexpCheckBarrier`.
|
||||
*/
|
||||
predicate regexpMatchGuardChecks(Guard guard, Expr e, boolean branch) {
|
||||
exists(Method method, MethodCall mc |
|
||||
method = mc.getMethod() and
|
||||
guard = mc and
|
||||
branch = true
|
||||
|
|
||||
e = mc.(RegexExecutionExpr::Range).getString()
|
||||
or
|
||||
// Other `matches` methods.
|
||||
method.getName() = "matches" and
|
||||
e = mc.getQualifier()
|
||||
)
|
||||
exists(RegexExecutionExpr::Range ree | not ree instanceof Annotation |
|
||||
guard = ree and
|
||||
e = ree.getString()
|
||||
) and
|
||||
branch = true
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -62,5 +56,12 @@ predicate regexpMatchGuardChecks(Guard guard, Expr e, boolean branch) {
|
||||
class RegexpCheckBarrier extends DataFlow::Node {
|
||||
RegexpCheckBarrier() {
|
||||
this = DataFlow::BarrierGuard<regexpMatchGuardChecks/3>::getABarrierNode()
|
||||
or
|
||||
// Annotations don't fit into the model of barrier guards because the
|
||||
// annotation doesn't dominate the sanitized expression, so we instead
|
||||
// treat them as barriers directly.
|
||||
exists(RegexExecutionExpr::Range ree | ree instanceof Annotation |
|
||||
this.asExpr() = ree.getString()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user