@@ -7,40 +7,30 @@ private import semmle.code.configfiles.ConfigFiles
7
7
private import semmle.code.xml.MavenPom
8
8
9
9
/** The parent node of the `org.springframework.boot` group. */
10
- class SpringBootParent extends Parent {
10
+ private class SpringBootParent extends Parent {
11
11
SpringBootParent ( ) { this .getGroup ( ) .getValue ( ) = "org.springframework.boot" }
12
12
}
13
13
14
- /** Class of Spring Boot dependencies. */
14
+ // TODO: private once done with version string debugging in alert msg.
15
+ /** A `Pom` with a Spring Boot parent node. */
15
16
class SpringBootPom extends Pom {
16
17
SpringBootPom ( ) { this .getParentElement ( ) instanceof SpringBootParent }
17
18
18
- /** Holds if the Spring Boot Actuator module `spring-boot-starter-actuator` is used in the project. */
19
- predicate isSpringBootActuatorUsed ( ) {
20
- this .getADependency ( ) .getArtifact ( ) .getValue ( ) = "spring-boot-starter-actuator"
21
- }
22
-
23
- /**
24
- * Holds if the Spring Boot Security module is used in the project, which brings in other security
25
- * related libraries.
26
- */
19
+ /** Holds if the Spring Boot Security module is used in the project. */
27
20
predicate isSpringBootSecurityUsed ( ) {
28
21
this .getADependency ( ) .getArtifact ( ) .getValue ( ) = "spring-boot-starter-security"
29
22
}
30
23
}
31
24
32
- /** The properties file `application.properties`. */
33
- class ApplicationPropertiesFile extends File {
34
- ApplicationPropertiesFile ( ) { this .getBaseName ( ) = "application.properties" }
35
- }
36
-
37
- /** A name-value pair stored in an `application.properties` file. */
38
- class ApplicationPropertiesConfigPair extends ConfigPair {
39
- ApplicationPropertiesConfigPair ( ) { this .getFile ( ) instanceof ApplicationPropertiesFile }
25
+ /** A dependency with artifactId `spring-boot-starter-actuator`. */
26
+ class SpringBootStarterActuatorDependency extends Dependency {
27
+ SpringBootStarterActuatorDependency ( ) {
28
+ this .getArtifact ( ) .getValue ( ) = "spring-boot-starter-actuator"
29
+ }
40
30
}
41
31
42
- /** The configuration property `management.security.enabled`. */
43
- class ManagementSecurityConfig extends ApplicationPropertiesConfigPair {
32
+ /** The Spring Boot configuration property `management.security.enabled`. */
33
+ private class ManagementSecurityConfig extends JavaProperty {
44
34
ManagementSecurityConfig ( ) { this .getNameElement ( ) .getName ( ) = "management.security.enabled" }
45
35
46
36
/** Gets the whitespace-trimmed value of this property. */
@@ -50,8 +40,8 @@ class ManagementSecurityConfig extends ApplicationPropertiesConfigPair {
50
40
predicate hasSecurityDisabled ( ) { this .getValue ( ) = "false" }
51
41
}
52
42
53
- /** The configuration property `management.endpoints.web.exposure.include`. */
54
- class ManagementEndPointInclude extends ApplicationPropertiesConfigPair {
43
+ /** The Spring Boot configuration property `management.endpoints.web.exposure.include`. */
44
+ private class ManagementEndPointInclude extends JavaProperty {
55
45
ManagementEndPointInclude ( ) {
56
46
this .getNameElement ( ) .getName ( ) = "management.endpoints.web.exposure.include"
57
47
}
@@ -62,13 +52,13 @@ class ManagementEndPointInclude extends ApplicationPropertiesConfigPair {
62
52
63
53
private newtype TOption =
64
54
TNone ( ) or
65
- TSome ( ApplicationPropertiesConfigPair ap )
55
+ TSome ( JavaProperty jp )
66
56
67
57
/**
68
58
* An option type that is either a singleton `None` or a `Some` wrapping
69
- * the `ApplicationPropertiesConfigPair ` type.
59
+ * the `JavaProperty ` type.
70
60
*/
71
- class ApplicationPropertiesOption extends TOption {
61
+ class JavaPropertyOption extends TOption {
72
62
/** Gets a textual representation of this element. */
73
63
string toString ( ) {
74
64
this = TNone ( ) and result = "(none)"
@@ -80,48 +70,50 @@ class ApplicationPropertiesOption extends TOption {
80
70
Location getLocation ( ) { result = this .asSome ( ) .getLocation ( ) }
81
71
82
72
/** Gets the wrapped element, if any. */
83
- ApplicationPropertiesConfigPair asSome ( ) { this = TSome ( result ) }
73
+ JavaProperty asSome ( ) { this = TSome ( result ) }
84
74
85
75
/** Holds if this option is the singleton `None`. */
86
76
predicate isNone ( ) { this = TNone ( ) }
87
77
}
88
78
89
79
/**
90
- * Holds if `ApplicationProperties` ap of a repository managed by `SpringBootPom` pom
91
- * has a vulnerable configuration of Spring Boot Actuator management endpoints.
80
+ * Holds if `JavaPropertyOption` jpOption of a repository using `SpringBootStarterActuatorDependency`
81
+ * d exposes sensitive Spring Boot Actuator endpoints.
92
82
*/
93
- predicate hasConfidentialEndPointExposed ( SpringBootPom pom , ApplicationPropertiesOption apOption ) {
94
- pom .isSpringBootActuatorUsed ( ) and
95
- not pom .isSpringBootSecurityUsed ( ) and
96
- exists ( ApplicationPropertiesFile apFile |
97
- apFile
83
+ predicate exposesSensitiveEndPoint (
84
+ SpringBootStarterActuatorDependency d , JavaPropertyOption jpOption
85
+ ) {
86
+ exists ( PropertiesFile propFile , SpringBootPom pom |
87
+ d = pom .getADependency ( ) and
88
+ not pom .isSpringBootSecurityUsed ( ) and
89
+ propFile
98
90
.getParentContainer ( )
99
91
.getAbsolutePath ( )
100
92
.matches ( pom .getFile ( ) .getParentContainer ( ) .getAbsolutePath ( ) + "%" ) and // in the same sub-directory
101
93
exists ( string springBootVersion |
102
94
springBootVersion = pom .getParentElement ( ) .getVersionString ( )
103
95
|
104
96
springBootVersion .regexpMatch ( "1\\.[0-4].*" ) and // version 1.0, 1.1, ..., 1.4
105
- not exists ( ManagementSecurityConfig me | me .getFile ( ) = apFile ) and
106
- apOption .isNone ( )
97
+ not exists ( ManagementSecurityConfig me | me .getFile ( ) = propFile ) and
98
+ jpOption .isNone ( )
107
99
or
108
100
springBootVersion .regexpMatch ( "1\\.[0-5].*" ) and // version 1.0, 1.1, ..., 1.5
109
101
exists ( ManagementSecurityConfig me |
110
- me .hasSecurityDisabled ( ) and me .getFile ( ) = apFile and me = apOption .asSome ( )
102
+ me .hasSecurityDisabled ( ) and me .getFile ( ) = propFile and me = jpOption .asSome ( )
111
103
)
112
104
or
113
105
springBootVersion .matches ( [ "2.%" , "3.%" ] ) and //version 2.x and 3.x
114
106
exists ( ManagementEndPointInclude mi |
115
- mi .getFile ( ) = apFile and
116
- mi = apOption .asSome ( ) and
107
+ mi .getFile ( ) = propFile and
108
+ mi = jpOption .asSome ( ) and
117
109
(
118
- mi .getValue ( ) = "*" // all endpoints are enabled
110
+ mi .getValue ( ) = "*" // all endpoints are exposed
119
111
or
120
112
mi .getValue ( )
121
113
.matches ( [
122
114
"%dump%" , "%trace%" , "%logfile%" , "%shutdown%" , "%startup%" , "%mappings%" ,
123
115
"%env%" , "%beans%" , "%sessions%"
124
- ] ) // confidential endpoints to check although all endpoints apart from '/health' are considered sensitive by Spring
116
+ ] ) // sensitive endpoints to check although all endpoints apart from '/health' are considered sensitive by Spring
125
117
)
126
118
)
127
119
)
0 commit comments