@@ -7,41 +7,33 @@ 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 {
44- ManagementSecurityConfig ( ) { this .getNameElement ( ) .getName ( ) = "management.security.enabled" }
32+ /** The Spring Boot configuration property `management.security.enabled`. */
33+ private class ManagementSecurityEnabledProperty extends JavaProperty {
34+ ManagementSecurityEnabledProperty ( ) {
35+ this .getNameElement ( ) .getName ( ) = "management.security.enabled"
36+ }
4537
4638 /** Gets the whitespace-trimmed value of this property. */
4739 string getValue ( ) { result = this .getValueElement ( ) .getValue ( ) .trim ( ) }
@@ -50,9 +42,9 @@ class ManagementSecurityConfig extends ApplicationPropertiesConfigPair {
5042 predicate hasSecurityDisabled ( ) { this .getValue ( ) = "false" }
5143}
5244
53- /** The configuration property `management.endpoints.web.exposure.include`. */
54- class ManagementEndPointInclude extends ApplicationPropertiesConfigPair {
55- ManagementEndPointInclude ( ) {
45+ /** The Spring Boot configuration property `management.endpoints.web.exposure.include`. */
46+ private class ManagementEndpointsIncludeProperty extends JavaProperty {
47+ ManagementEndpointsIncludeProperty ( ) {
5648 this .getNameElement ( ) .getName ( ) = "management.endpoints.web.exposure.include"
5749 }
5850
@@ -62,13 +54,13 @@ class ManagementEndPointInclude extends ApplicationPropertiesConfigPair {
6254
6355private newtype TOption =
6456 TNone ( ) or
65- TSome ( ApplicationPropertiesConfigPair ap )
57+ TSome ( JavaProperty jp )
6658
6759/**
6860 * An option type that is either a singleton `None` or a `Some` wrapping
69- * the `ApplicationPropertiesConfigPair ` type.
61+ * the `JavaProperty ` type.
7062 */
71- class ApplicationPropertiesOption extends TOption {
63+ class JavaPropertyOption extends TOption {
7264 /** Gets a textual representation of this element. */
7365 string toString ( ) {
7466 this = TNone ( ) and result = "(none)"
@@ -80,48 +72,50 @@ class ApplicationPropertiesOption extends TOption {
8072 Location getLocation ( ) { result = this .asSome ( ) .getLocation ( ) }
8173
8274 /** Gets the wrapped element, if any. */
83- ApplicationPropertiesConfigPair asSome ( ) { this = TSome ( result ) }
75+ JavaProperty asSome ( ) { this = TSome ( result ) }
8476
8577 /** Holds if this option is the singleton `None`. */
8678 predicate isNone ( ) { this = TNone ( ) }
8779}
8880
8981/**
90- * Holds if `ApplicationProperties` ap of a repository managed by `SpringBootPom` pom
91- * has a vulnerable configuration of Spring Boot Actuator management endpoints.
82+ * Holds if `JavaPropertyOption` jpOption of a repository using `SpringBootStarterActuatorDependency`
83+ * d exposes sensitive Spring Boot Actuator endpoints.
9284 */
93- predicate hasConfidentialEndPointExposed ( SpringBootPom pom , ApplicationPropertiesOption apOption ) {
94- pom .isSpringBootActuatorUsed ( ) and
95- not pom .isSpringBootSecurityUsed ( ) and
96- exists ( ApplicationPropertiesFile apFile |
97- apFile
85+ predicate exposesSensitiveEndpoint (
86+ SpringBootStarterActuatorDependency d , JavaPropertyOption jpOption
87+ ) {
88+ exists ( PropertiesFile propFile , SpringBootPom pom |
89+ d = pom .getADependency ( ) and
90+ not pom .isSpringBootSecurityUsed ( ) and
91+ propFile
9892 .getParentContainer ( )
9993 .getAbsolutePath ( )
10094 .matches ( pom .getFile ( ) .getParentContainer ( ) .getAbsolutePath ( ) + "%" ) and // in the same sub-directory
10195 exists ( string springBootVersion |
10296 springBootVersion = pom .getParentElement ( ) .getVersionString ( )
10397 |
10498 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 ( )
99+ not exists ( ManagementSecurityEnabledProperty ep | ep .getFile ( ) = propFile ) and
100+ jpOption .isNone ( )
107101 or
108102 springBootVersion .regexpMatch ( "1\\.[0-5].*" ) and // version 1.0, 1.1, ..., 1.5
109- exists ( ManagementSecurityConfig me |
110- me .hasSecurityDisabled ( ) and me .getFile ( ) = apFile and me = apOption .asSome ( )
103+ exists ( ManagementSecurityEnabledProperty ep |
104+ ep .hasSecurityDisabled ( ) and ep .getFile ( ) = propFile and ep = jpOption .asSome ( )
111105 )
112106 or
113107 springBootVersion .matches ( [ "2.%" , "3.%" ] ) and //version 2.x and 3.x
114- exists ( ManagementEndPointInclude mi |
115- mi .getFile ( ) = apFile and
116- mi = apOption .asSome ( ) and
108+ exists ( ManagementEndpointsIncludeProperty ip |
109+ ip .getFile ( ) = propFile and
110+ ip = jpOption .asSome ( ) and
117111 (
118- mi .getValue ( ) = "*" // all endpoints are enabled
112+ ip .getValue ( ) = "*" // all endpoints are exposed
119113 or
120- mi .getValue ( )
114+ ip .getValue ( )
121115 .matches ( [
122116 "%dump%" , "%trace%" , "%logfile%" , "%shutdown%" , "%startup%" , "%mappings%" ,
123117 "%env%" , "%beans%" , "%sessions%"
124- ] ) // confidential endpoints to check although all endpoints apart from '/health' are considered sensitive by Spring
118+ ] ) // sensitive endpoints to check although all endpoints apart from '/health' are considered sensitive by Spring
125119 )
126120 )
127121 )
0 commit comments