Skip to content

Commit b7c1e1e

Browse files
authored
Merge pull request #20006 from jcogs33/jcogs33/java/insecure-spring-actuator-config-promotion
Java: Promote Insecure Spring Boot Actuator Configuration query from experimental
2 parents 499e432 + 3675e4b commit b7c1e1e

File tree

46 files changed

+695
-233
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+695
-233
lines changed

java/ql/integration-tests/java/query-suite/java-code-scanning.qls.expected

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ ql/java/ql/src/Security/CWE/CWE-113/ResponseSplitting.ql
2727
ql/java/ql/src/Security/CWE/CWE-1204/StaticInitializationVector.ql
2828
ql/java/ql/src/Security/CWE/CWE-134/ExternallyControlledFormatString.ql
2929
ql/java/ql/src/Security/CWE/CWE-200/SpringBootActuators.ql
30+
ql/java/ql/src/Security/CWE/CWE-200/SpringBootActuatorsConfig/SpringBootActuatorsConfig.ql
3031
ql/java/ql/src/Security/CWE/CWE-209/SensitiveDataExposureThroughErrorMessage.ql
3132
ql/java/ql/src/Security/CWE/CWE-209/StackTraceExposure.ql
3233
ql/java/ql/src/Security/CWE/CWE-266/IntentUriPermissionManipulation.ql

java/ql/integration-tests/java/query-suite/java-security-and-quality.qls.expected

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ ql/java/ql/src/Security/CWE/CWE-200/AndroidSensitiveTextField.ql
143143
ql/java/ql/src/Security/CWE/CWE-200/AndroidWebViewSettingsAllowsContentAccess.ql
144144
ql/java/ql/src/Security/CWE/CWE-200/AndroidWebViewSettingsFileAccess.ql
145145
ql/java/ql/src/Security/CWE/CWE-200/SpringBootActuators.ql
146+
ql/java/ql/src/Security/CWE/CWE-200/SpringBootActuatorsConfig/SpringBootActuatorsConfig.ql
146147
ql/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.ql
147148
ql/java/ql/src/Security/CWE/CWE-209/SensitiveDataExposureThroughErrorMessage.ql
148149
ql/java/ql/src/Security/CWE/CWE-209/StackTraceExposure.ql

java/ql/integration-tests/java/query-suite/java-security-extended.qls.expected

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ ql/java/ql/src/Security/CWE/CWE-200/AndroidSensitiveTextField.ql
4646
ql/java/ql/src/Security/CWE/CWE-200/AndroidWebViewSettingsAllowsContentAccess.ql
4747
ql/java/ql/src/Security/CWE/CWE-200/AndroidWebViewSettingsFileAccess.ql
4848
ql/java/ql/src/Security/CWE/CWE-200/SpringBootActuators.ql
49+
ql/java/ql/src/Security/CWE/CWE-200/SpringBootActuatorsConfig/SpringBootActuatorsConfig.ql
4950
ql/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.ql
5051
ql/java/ql/src/Security/CWE/CWE-209/SensitiveDataExposureThroughErrorMessage.ql
5152
ql/java/ql/src/Security/CWE/CWE-209/StackTraceExposure.ql

java/ql/integration-tests/java/query-suite/not_included_in_qls.expected

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,6 @@ ql/java/ql/src/Violations of Best Practice/legacy/ParameterAssignment.ql
195195
ql/java/ql/src/Violations of Best Practice/legacy/UnnecessaryCast.ql
196196
ql/java/ql/src/Violations of Best Practice/legacy/UnnecessaryImport.ql
197197
ql/java/ql/src/definitions.ql
198-
ql/java/ql/src/experimental/Security/CWE/CWE-016/InsecureSpringActuatorConfig.ql
199198
ql/java/ql/src/experimental/Security/CWE/CWE-020/Log4jJndiInjection.ql
200199
ql/java/ql/src/experimental/Security/CWE/CWE-036/OpenStream.ql
201200
ql/java/ql/src/experimental/Security/CWE/CWE-073/FilePathInjection.ql

java/ql/lib/semmle/code/configfiles/ConfigFiles.qll

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,12 @@ class ConfigValue extends @configValue, ConfigLocatable {
7070
override string toString() { result = this.getValue() }
7171
}
7272

73+
/** A `.properties` file. */
74+
class PropertiesFile extends File {
75+
PropertiesFile() { this.getExtension() = "properties" }
76+
}
77+
7378
/** A Java property is a name-value pair in a `.properties` file. */
7479
class JavaProperty extends ConfigPair {
75-
JavaProperty() { this.getFile().getExtension() = "properties" }
80+
JavaProperty() { this.getFile() instanceof PropertiesFile }
7681
}
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
/** Provides classes and predicates to reason about Spring Boot actuators exposed in configuration files. */
2+
overlay[local?]
3+
module;
4+
5+
import java
6+
private import semmle.code.configfiles.ConfigFiles
7+
private import semmle.code.xml.MavenPom
8+
9+
/** The parent node of the `org.springframework.boot` group. */
10+
private class SpringBootParent extends Parent {
11+
SpringBootParent() { this.getGroup().getValue() = "org.springframework.boot" }
12+
}
13+
14+
/** A `Pom` with a Spring Boot parent node. */
15+
private class SpringBootPom extends Pom {
16+
SpringBootPom() { this.getParentElement() instanceof SpringBootParent }
17+
18+
/** Holds if the Spring Boot Security module is used in the project. */
19+
predicate isSpringBootSecurityUsed() {
20+
this.getADependency().getArtifact().getValue() = "spring-boot-starter-security"
21+
}
22+
}
23+
24+
/** A dependency with artifactId `spring-boot-starter-actuator`. */
25+
class SpringBootStarterActuatorDependency extends Dependency {
26+
SpringBootStarterActuatorDependency() {
27+
this.getArtifact().getValue() = "spring-boot-starter-actuator"
28+
}
29+
}
30+
31+
/** The Spring Boot configuration property `management.security.enabled`. */
32+
private class ManagementSecurityEnabledProperty extends JavaProperty {
33+
ManagementSecurityEnabledProperty() {
34+
this.getNameElement().getName() = "management.security.enabled"
35+
}
36+
37+
/** Gets the whitespace-trimmed value of this property. */
38+
string getValue() { result = this.getValueElement().getValue().trim() }
39+
40+
/** Holds if `management.security.enabled` is set to `false`. */
41+
predicate hasSecurityDisabled() { this.getValue() = "false" }
42+
}
43+
44+
/**
45+
* The Spring Boot configuration property `management.endpoints.web.exposure.include`
46+
* or `management.endpoints.web.expose`.
47+
*/
48+
private class ManagementEndpointsExposeProperty extends JavaProperty {
49+
ManagementEndpointsExposeProperty() {
50+
this.getNameElement().getName() = "management.endpoints.web." + ["exposure.include", "expose"]
51+
}
52+
53+
/** Gets the whitespace-trimmed value of this property. */
54+
string getValue() { result = this.getValueElement().getValue().trim() }
55+
}
56+
57+
private newtype TOption =
58+
TNone() or
59+
TSome(JavaProperty jp)
60+
61+
/**
62+
* An option type that is either a singleton `None` or a `Some` wrapping
63+
* the `JavaProperty` type.
64+
*/
65+
class JavaPropertyOption extends TOption {
66+
/** Gets a textual representation of this element. */
67+
string toString() {
68+
this = TNone() and result = "(none)"
69+
or
70+
result = this.asSome().toString()
71+
}
72+
73+
/** Gets the location of this element. */
74+
Location getLocation() { result = this.asSome().getLocation() }
75+
76+
/** Gets the wrapped element, if any. */
77+
JavaProperty asSome() { this = TSome(result) }
78+
79+
/** Holds if this option is the singleton `None`. */
80+
predicate isNone() { this = TNone() }
81+
}
82+
83+
/**
84+
* Holds if `JavaPropertyOption` jpOption of a repository using `SpringBootStarterActuatorDependency`
85+
* d exposes sensitive Spring Boot Actuator endpoints.
86+
*/
87+
predicate exposesSensitiveEndpoint(
88+
SpringBootStarterActuatorDependency d, JavaPropertyOption jpOption
89+
) {
90+
exists(PropertiesFile propFile, SpringBootPom pom |
91+
d = pom.getADependency() and
92+
not pom.isSpringBootSecurityUsed() and
93+
propFile
94+
.getParentContainer()
95+
.getAbsolutePath()
96+
.matches(pom.getFile().getParentContainer().getAbsolutePath() + "%") and // in the same sub-directory
97+
exists(string springBootVersion |
98+
springBootVersion = pom.getParentElement().getVersionString()
99+
|
100+
springBootVersion.regexpMatch("1\\.[0-4].*") and // version 1.0, 1.1, ..., 1.4
101+
not exists(ManagementSecurityEnabledProperty ep | ep.getFile() = propFile) and
102+
jpOption.isNone()
103+
or
104+
springBootVersion.regexpMatch("1\\.[0-5].*") and // version 1.0, 1.1, ..., 1.5
105+
exists(ManagementSecurityEnabledProperty ep |
106+
ep.hasSecurityDisabled() and ep.getFile() = propFile and ep = jpOption.asSome()
107+
)
108+
or
109+
springBootVersion.matches(["2.%", "3.%"]) and //version 2.x and 3.x
110+
exists(ManagementEndpointsExposeProperty ep |
111+
ep.getFile() = propFile and
112+
ep = jpOption.asSome() and
113+
(
114+
// all endpoints are exposed
115+
ep.getValue() = "*"
116+
or
117+
// version 2.x: exposes health and info only by default
118+
springBootVersion.matches("2.%") and
119+
not ep.getValue() = ["health", "info"]
120+
or
121+
// version 3.x: exposes health only by default
122+
springBootVersion.matches("3.%") and
123+
not ep.getValue() = "health"
124+
)
125+
)
126+
)
127+
)
128+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<!DOCTYPE qhelp PUBLIC "-//Semmle//qhelp//EN" "qhelp.dtd">
2+
<qhelp>
3+
<overview>
4+
<p>Spring Boot includes features called actuators that let you monitor and interact with your web
5+
application. Exposing unprotected actuator endpoints through configuration files can lead to
6+
information disclosure or even to remote code execution.</p>
7+
</overview>
8+
9+
<recommendation>
10+
<p>Since actuator endpoints may contain sensitive information, carefully consider when to expose them,
11+
and secure them as you would any sensitive URL. If you need to expose actuator endpoints, use Spring
12+
Security, which secures actuators by default, or define a custom security configuration.
13+
</p>
14+
</recommendation>
15+
16+
<example>
17+
<p>The following examples show <code>application.properties</code> configurations that expose sensitive
18+
actuator endpoints.</p>
19+
<sample src="application_bad.properties" />
20+
21+
<p>The below configurations ensure that sensitive actuator endpoints are not exposed.</p>
22+
<sample src="application_good.properties" />
23+
24+
<p>To use Spring Security, which secures actuators by default, add the <code>spring-boot-starter-security</code>
25+
dependency in your Maven <code>pom.xml</code> file.</p>
26+
<sample src="pom_good.xml" />
27+
</example>
28+
29+
<references>
30+
<li>
31+
Spring Boot Reference Documentation:
32+
<a href="https://docs.spring.io/spring-boot/reference/actuator/endpoints.html">Endpoints</a>.
33+
</li>
34+
<li>
35+
HackerOne Report:
36+
<a href="https://hackerone.com/reports/862589">Spring Actuator endpoints publicly available, leading to account takeover</a>
37+
</li>
38+
</references>
39+
</qhelp>
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/**
2+
* @name Exposed Spring Boot actuators in configuration file
3+
* @description Exposing Spring Boot actuators through configuration files may lead to information leak from
4+
* the internal application, or even to remote code execution.
5+
* @kind problem
6+
* @problem.severity error
7+
* @security-severity 6.5
8+
* @precision high
9+
* @id java/spring-boot-exposed-actuators-config
10+
* @tags security
11+
* external/cwe/cwe-200
12+
*/
13+
14+
import java
15+
import semmle.code.xml.MavenPom
16+
import semmle.code.java.security.SpringBootActuatorsConfigQuery
17+
18+
from SpringBootStarterActuatorDependency d, JavaPropertyOption jpOption
19+
where exposesSensitiveEndpoint(d, jpOption)
20+
select d, "Insecure Spring Boot actuator $@ exposes sensitive endpoints.", jpOption, "configuration"
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# vulnerable configuration (Spring Boot 1.0 - 1.4): exposes endpoints by default
2+
3+
# vulnerable configuration (Spring Boot 1.5): false value exposes endpoints
4+
management.security.enabled=false
5+
6+
# vulnerable configuration (Spring Boot 2.x): exposes all endpoints
7+
management.endpoints.web.exposure.include=*
8+
9+
# vulnerable configuration (Spring Boot 3.x): exposes all endpoints
10+
management.endpoints.web.exposure.include=*
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# safe configuration (Spring Boot 1.0 - 1.4)
2+
management.security.enabled=true
3+
4+
# safe configuration (Spring Boot 1.5+)
5+
management.security.enabled=true
6+
7+
# safe configuration (Spring Boot 2.x): exposes health and info only by default
8+
management.endpoints.web.exposure.include=health,info
9+
10+
# safe configuration (Spring Boot 3.x): exposes health only by default
11+
management.endpoints.web.exposure.include=health

0 commit comments

Comments
 (0)