@@ -7,40 +7,30 @@ private import semmle.code.configfiles.ConfigFiles
77private import semmle.code.xml.MavenPom
88
99/** The parent node of the `org.springframework.boot` group. */
10- class SpringBootParent extends Parent {
10+ private class SpringBootParent extends Parent {
1111 SpringBootParent ( ) { this .getGroup ( ) .getValue ( ) = "org.springframework.boot" }
1212}
1313
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. */
1516class SpringBootPom extends Pom {
1617 SpringBootPom ( ) { this .getParentElement ( ) instanceof SpringBootParent }
1718
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. */
2720 predicate isSpringBootSecurityUsed ( ) {
2821 this .getADependency ( ) .getArtifact ( ) .getValue ( ) = "spring-boot-starter-security"
2922 }
3023}
3124
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+ }
4030}
4131
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 {
4434 ManagementSecurityConfig ( ) { this .getNameElement ( ) .getName ( ) = "management.security.enabled" }
4535
4636 /** Gets the whitespace-trimmed value of this property. */
@@ -50,8 +40,8 @@ class ManagementSecurityConfig extends ApplicationPropertiesConfigPair {
5040 predicate hasSecurityDisabled ( ) { this .getValue ( ) = "false" }
5141}
5242
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 {
5545 ManagementEndPointInclude ( ) {
5646 this .getNameElement ( ) .getName ( ) = "management.endpoints.web.exposure.include"
5747 }
@@ -62,13 +52,13 @@ class ManagementEndPointInclude extends ApplicationPropertiesConfigPair {
6252
6353private newtype TOption =
6454 TNone ( ) or
65- TSome ( ApplicationPropertiesConfigPair ap )
55+ TSome ( JavaProperty jp )
6656
6757/**
6858 * An option type that is either a singleton `None` or a `Some` wrapping
69- * the `ApplicationPropertiesConfigPair ` type.
59+ * the `JavaProperty ` type.
7060 */
71- class ApplicationPropertiesOption extends TOption {
61+ class JavaPropertyOption extends TOption {
7262 /** Gets a textual representation of this element. */
7363 string toString ( ) {
7464 this = TNone ( ) and result = "(none)"
@@ -80,48 +70,50 @@ class ApplicationPropertiesOption extends TOption {
8070 Location getLocation ( ) { result = this .asSome ( ) .getLocation ( ) }
8171
8272 /** Gets the wrapped element, if any. */
83- ApplicationPropertiesConfigPair asSome ( ) { this = TSome ( result ) }
73+ JavaProperty asSome ( ) { this = TSome ( result ) }
8474
8575 /** Holds if this option is the singleton `None`. */
8676 predicate isNone ( ) { this = TNone ( ) }
8777}
8878
8979/**
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.
9282 */
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
9890 .getParentContainer ( )
9991 .getAbsolutePath ( )
10092 .matches ( pom .getFile ( ) .getParentContainer ( ) .getAbsolutePath ( ) + "%" ) and // in the same sub-directory
10193 exists ( string springBootVersion |
10294 springBootVersion = pom .getParentElement ( ) .getVersionString ( )
10395 |
10496 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 ( )
10799 or
108100 springBootVersion .regexpMatch ( "1\\.[0-5].*" ) and // version 1.0, 1.1, ..., 1.5
109101 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 ( )
111103 )
112104 or
113105 springBootVersion .matches ( [ "2.%" , "3.%" ] ) and //version 2.x and 3.x
114106 exists ( ManagementEndPointInclude mi |
115- mi .getFile ( ) = apFile and
116- mi = apOption .asSome ( ) and
107+ mi .getFile ( ) = propFile and
108+ mi = jpOption .asSome ( ) and
117109 (
118- mi .getValue ( ) = "*" // all endpoints are enabled
110+ mi .getValue ( ) = "*" // all endpoints are exposed
119111 or
120112 mi .getValue ( )
121113 .matches ( [
122114 "%dump%" , "%trace%" , "%logfile%" , "%shutdown%" , "%startup%" , "%mappings%" ,
123115 "%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
125117 )
126118 )
127119 )
0 commit comments