Skip to content

Commit eeac7e3

Browse files
committed
Query to detect insecure configuration of Spring Boot Actuator
1 parent 0edae89 commit eeac7e3

File tree

10 files changed

+357
-0
lines changed

10 files changed

+357
-0
lines changed
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<!DOCTYPE qhelp PUBLIC "-//Semmle//qhelp//EN" "qhelp.dtd">
2+
<qhelp>
3+
<overview>
4+
<p>Spring Boot is a popular framework that facilitates the development of stand-alone applications
5+
and micro services. Spring Boot Actuator helps to expose production-ready support features against
6+
Spring Boot applications.</p>
7+
8+
<p>Endpoints of Spring Boot Actuator allow to monitor and interact with a Spring Boot application.
9+
Exposing unprotected actuator endpoints through configuration files can lead to information disclosure
10+
or even remote code execution vulnerability.</p>
11+
12+
<p>Rather than programmatically permitting endpoint requests or enforcing access control, frequently
13+
developers simply leave management endpoints publicly accessible in the application configuration file
14+
<code>application.properties</code> without enforcing access control through Spring Security.</p>
15+
</overview>
16+
17+
<recommendation>
18+
<p>Declare the Spring Boot Starter Security module in XML configuration or programmatically enforce
19+
security checks on management endpoints using Spring Security. Otherwise accessing management endpoints
20+
on a different HTTP port other than the port that the web application is listening on also helps to
21+
improve the security.</p>
22+
</recommendation>
23+
24+
<example>
25+
<p>The following examples show both 'BAD' and 'GOOD' configurations. In the 'BAD' configuration,
26+
no security module is declared and sensitive management endpoints are exposed. In the 'GOOD' configuration,
27+
security is enforced and only endpoints requiring exposure are exposed.</p>
28+
<sample src="pom_good.xml" />
29+
<sample src="pom_bad.xml" />
30+
<sample src="application.properties" />
31+
</example>
32+
33+
<references>
34+
<li>
35+
Spring Boot documentation:
36+
<a href="https://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-features.html">Spring Boot Actuator: Production-ready Features</a>
37+
</li>
38+
<li>
39+
VERACODE Blog:
40+
<a href="https://www.veracode.com/blog/research/exploiting-spring-boot-actuators">Exploiting Spring Boot Actuators</a>
41+
</li>
42+
<li>
43+
HackerOne Report:
44+
<a href="https://hackerone.com/reports/862589">Spring Actuator endpoints publicly available, leading to account takeover</a>
45+
</li>
46+
</references>
47+
</qhelp>
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
/**
2+
* @name Insecure Spring Boot Actuator Configuration
3+
* @description Exposed Spring Boot Actuator through configuration files without declarative or procedural security enforcement leads to information leak or even remote code execution.
4+
* @kind problem
5+
* @id java/insecure-spring-actuator-config
6+
* @tags security
7+
* external/cwe-016
8+
*/
9+
10+
import java
11+
import semmle.code.configfiles.ConfigFiles
12+
import semmle.code.java.security.SensitiveActions
13+
import semmle.code.xml.MavenPom
14+
15+
/** The parent node of the `org.springframework.boot` group. */
16+
class SpringBootParent extends Parent {
17+
SpringBootParent() { this.getGroup().getValue() = "org.springframework.boot" }
18+
}
19+
20+
/** Class of Spring Boot dependencies. */
21+
class SpringBootPom extends Pom {
22+
SpringBootPom() { this.getParentElement() instanceof SpringBootParent }
23+
24+
/** Holds if the Spring Boot Actuator module `spring-boot-starter-actuator` is used in the project. */
25+
predicate isSpringBootActuatorUsed() {
26+
this.getADependency().getArtifact().getValue() = "spring-boot-starter-actuator"
27+
}
28+
29+
/** Holds if the Spring Boot Security module is used in the project, which brings in other security related libraries. */
30+
predicate isSpringBootSecurityUsed() {
31+
this.getADependency().getArtifact().getValue() = "spring-boot-starter-security"
32+
}
33+
}
34+
35+
/** The properties file `application.properties`. */
36+
class ApplicationProperties extends ConfigPair {
37+
ApplicationProperties() { this.getFile().getBaseName() = "application.properties" }
38+
}
39+
40+
/** The configuration property `management.security.enabled`. */
41+
class ManagementSecurityEnabled extends ApplicationProperties {
42+
ManagementSecurityEnabled() { this.getNameElement().getName() = "management.security.enabled" }
43+
44+
string getManagementSecurityEnabled() { result = this.getValueElement().getValue() }
45+
46+
predicate hasSecurityDisabled() { getManagementSecurityEnabled() = "false" }
47+
48+
predicate hasSecurityEnabled() { getManagementSecurityEnabled() = "true" }
49+
}
50+
51+
/** The configuration property `management.endpoints.web.exposure.include`. */
52+
class ManagementEndPointInclude extends ApplicationProperties {
53+
ManagementEndPointInclude() {
54+
this.getNameElement().getName() = "management.endpoints.web.exposure.include"
55+
}
56+
57+
string getManagementEndPointInclude() { result = this.getValueElement().getValue().trim() }
58+
}
59+
60+
/** The configuration property `management.endpoints.web.exposure.exclude`. */
61+
class ManagementEndPointExclude extends ApplicationProperties {
62+
ManagementEndPointExclude() {
63+
this.getNameElement().getName() = "management.endpoints.web.exposure.exclude"
64+
}
65+
66+
string getManagementEndPointExclude() { result = this.getValueElement().getValue().trim() }
67+
}
68+
69+
/** Holds if an application handles sensitive information judging by its variable names. */
70+
predicate isProtectedApp() {
71+
exists(VarAccess va | va.getVariable().getName().regexpMatch(getCommonSensitiveInfoRegex()))
72+
}
73+
74+
from SpringBootPom pom, ApplicationProperties ap, Dependency d
75+
where
76+
isProtectedApp() and
77+
pom.isSpringBootActuatorUsed() and
78+
not pom.isSpringBootSecurityUsed() and
79+
ap.getFile()
80+
.getParentContainer()
81+
.getAbsolutePath()
82+
.matches(pom.getFile().getParentContainer().getAbsolutePath() + "%") and // in the same sub-directory
83+
exists(string s | s = pom.getParentElement().getVersionString() |
84+
s.regexpMatch("1\\.[0|1|2|3|4].*") and
85+
not exists(ManagementSecurityEnabled me |
86+
me.hasSecurityEnabled() and me.getFile() = ap.getFile()
87+
)
88+
or
89+
s.regexpMatch("1\\.5.*") and
90+
exists(ManagementSecurityEnabled me | me.hasSecurityDisabled() and me.getFile() = ap.getFile())
91+
or
92+
s.regexpMatch("2.*") and
93+
exists(ManagementEndPointInclude mi |
94+
mi.getFile() = ap.getFile() and
95+
(
96+
mi.getManagementEndPointInclude() = "*" // all endpoints are enabled
97+
or
98+
mi.getManagementEndPointInclude()
99+
.matches([
100+
"%dump%", "%trace%", "%logfile%", "%shutdown%", "%startup%", "%mappings%", "%env%",
101+
"%beans%", "%sessions%"
102+
]) // all endpoints apart from '/health' and '/info' are considered sensitive
103+
) and
104+
not exists(ManagementEndPointExclude mx |
105+
mx.getFile() = ap.getFile() and
106+
mx.getManagementEndPointExclude() = mi.getManagementEndPointInclude()
107+
)
108+
)
109+
) and
110+
d = pom.getADependency() and
111+
d.getArtifact().getValue() = "spring-boot-starter-actuator"
112+
select d, "Insecure configuration of Spring Boot Actuator exposes sensitive endpoints."
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#management.endpoints.web.base-path=/admin
2+
3+
4+
#### BAD: All management endpoints are accessible ####
5+
# vulnerable configuration (spring boot 1.0 - 1.4): exposes actuators by default
6+
7+
# vulnerable configuration (spring boot 1.5+): requires value false to expose sensitive actuators
8+
management.security.enabled=false
9+
10+
# vulnerable configuration (spring boot 2+): exposes health and info only by default
11+
management.endpoints.web.exposure.include=*
12+
13+
14+
#### GOOD: All management endpoints have access control ####
15+
# safe configuration (spring boot 1.0 - 1.4): exposes actuators by default
16+
management.security.enabled=true
17+
18+
# safe configuration (spring boot 1.5+): requires value false to expose sensitive actuators
19+
management.security.enabled=true
20+
21+
# safe configuration (spring boot 2+): exposes health and info only by default
22+
management.endpoints.web.exposure.include=beans,info,health
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<modelVersion>4.0.0</modelVersion>
6+
7+
<groupId>spring-boot-actuator-app</groupId>
8+
<artifactId>spring-boot-actuator-app</artifactId>
9+
<version>1.0-SNAPSHOT</version>
10+
11+
<properties>
12+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
13+
<maven.compiler.source>1.8</maven.compiler.source>
14+
<maven.compiler.target>1.8</maven.compiler.target>
15+
</properties>
16+
17+
<parent>
18+
<groupId>org.springframework.boot</groupId>
19+
<artifactId>spring-boot-starter-parent</artifactId>
20+
<version>2.3.8.RELEASE</version>
21+
<relativePath/>
22+
</parent>
23+
24+
<dependencies>
25+
<dependency>
26+
<groupId>org.springframework.boot</groupId>
27+
<artifactId>spring-boot-starter-web</artifactId>
28+
</dependency>
29+
<dependency>
30+
<groupId>org.springframework.boot</groupId>
31+
<artifactId>spring-boot-starter-actuator</artifactId>
32+
</dependency>
33+
<dependency>
34+
<groupId>org.springframework.boot</groupId>
35+
<artifactId>spring-boot-devtools</artifactId>
36+
</dependency>
37+
38+
<!-- BAD: No Spring Security enabled -->
39+
<!-- dependency>
40+
<groupId>org.springframework.boot</groupId>
41+
<artifactId>spring-boot-starter-security</artifactId>
42+
</dependency -->
43+
44+
<dependency>
45+
<groupId>org.springframework.boot</groupId>
46+
<artifactId>spring-boot-test</artifactId>
47+
</dependency>
48+
</dependencies>
49+
50+
</project>
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<modelVersion>4.0.0</modelVersion>
6+
7+
<groupId>spring-boot-actuator-app</groupId>
8+
<artifactId>spring-boot-actuator-app</artifactId>
9+
<version>1.0-SNAPSHOT</version>
10+
11+
<properties>
12+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
13+
<maven.compiler.source>1.8</maven.compiler.source>
14+
<maven.compiler.target>1.8</maven.compiler.target>
15+
</properties>
16+
17+
<parent>
18+
<groupId>org.springframework.boot</groupId>
19+
<artifactId>spring-boot-starter-parent</artifactId>
20+
<version>2.3.8.RELEASE</version>
21+
<relativePath/>
22+
</parent>
23+
24+
<dependencies>
25+
<dependency>
26+
<groupId>org.springframework.boot</groupId>
27+
<artifactId>spring-boot-starter-web</artifactId>
28+
</dependency>
29+
<dependency>
30+
<groupId>org.springframework.boot</groupId>
31+
<artifactId>spring-boot-starter-actuator</artifactId>
32+
</dependency>
33+
<dependency>
34+
<groupId>org.springframework.boot</groupId>
35+
<artifactId>spring-boot-devtools</artifactId>
36+
</dependency>
37+
38+
<!-- GOOD: Enable Spring Security -->
39+
<dependency>
40+
<groupId>org.springframework.boot</groupId>
41+
<artifactId>spring-boot-starter-security</artifactId>
42+
</dependency>
43+
44+
<dependency>
45+
<groupId>org.springframework.boot</groupId>
46+
<artifactId>spring-boot-test</artifactId>
47+
</dependency>
48+
</dependencies>
49+
50+
</project>
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
| pom.xml:29:9:32:22 | dependency | Insecure configuration of Spring Boot Actuator exposes sensitive endpoints. |
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
experimental/Security/CWE/CWE-016/InsecureSpringActuatorConfig.ql
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import org.springframework.stereotype.Controller;
2+
import org.springframework.web.bind.annotation.RequestParam;
3+
import org.springframework.web.bind.annotation.RequestMapping;
4+
5+
@Controller
6+
public class SensitiveInfo {
7+
@RequestMapping
8+
public void handleLogin(@RequestParam String username, @RequestParam String password) throws Exception {
9+
if (!username.equals("") && password.equals("")) {
10+
//Blank processing
11+
}
12+
}
13+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#management.endpoints.web.base-path=/admin
2+
3+
# vulnerable configuration (spring boot 1.0 - 1.4): exposes actuators by default
4+
5+
# vulnerable configuration (spring boot 1.5+): requires value false to expose sensitive actuators
6+
management.security.enabled=false
7+
8+
# vulnerable configuration (spring boot 2+): exposes health and info only by default
9+
management.endpoints.web.exposure.include=*
10+
management.endpoints.web.exposure.exclude=beans
11+
12+
management.endpoint.shutdown.enabled=true
13+
14+
management.endpoint.health.show-details=when_authorized
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<modelVersion>4.0.0</modelVersion>
6+
7+
<groupId>spring-boot-actuator-app</groupId>
8+
<artifactId>spring-boot-actuator-app</artifactId>
9+
<version>1.0-SNAPSHOT</version>
10+
11+
<properties>
12+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
13+
<maven.compiler.source>1.8</maven.compiler.source>
14+
<maven.compiler.target>1.8</maven.compiler.target>
15+
</properties>
16+
17+
<parent>
18+
<groupId>org.springframework.boot</groupId>
19+
<artifactId>spring-boot-starter-parent</artifactId>
20+
<version>2.3.8.RELEASE</version>
21+
<relativePath/>
22+
</parent>
23+
24+
<dependencies>
25+
<dependency>
26+
<groupId>org.springframework.boot</groupId>
27+
<artifactId>spring-boot-starter-web</artifactId>
28+
</dependency>
29+
<dependency>
30+
<groupId>org.springframework.boot</groupId>
31+
<artifactId>spring-boot-starter-actuator</artifactId>
32+
</dependency>
33+
<dependency>
34+
<groupId>org.springframework.boot</groupId>
35+
<artifactId>spring-boot-devtools</artifactId>
36+
</dependency>
37+
<!-- dependency>
38+
<groupId>org.springframework.boot</groupId>
39+
<artifactId>spring-boot-starter-security</artifactId>
40+
</dependency -->
41+
<dependency>
42+
<groupId>org.springframework.boot</groupId>
43+
<artifactId>spring-boot-test</artifactId>
44+
</dependency>
45+
</dependencies>
46+
47+
</project>

0 commit comments

Comments
 (0)