Skip to content

Java: Promote Insecure Spring Boot Actuator Configuration query from experimental #20006

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 19 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ ql/java/ql/src/Security/CWE/CWE-113/ResponseSplitting.ql
ql/java/ql/src/Security/CWE/CWE-1204/StaticInitializationVector.ql
ql/java/ql/src/Security/CWE/CWE-134/ExternallyControlledFormatString.ql
ql/java/ql/src/Security/CWE/CWE-200/SpringBootActuators.ql
ql/java/ql/src/Security/CWE/CWE-200/SpringBootActuatorsConfig/SpringBootActuatorsConfig.ql
ql/java/ql/src/Security/CWE/CWE-209/SensitiveDataExposureThroughErrorMessage.ql
ql/java/ql/src/Security/CWE/CWE-209/StackTraceExposure.ql
ql/java/ql/src/Security/CWE/CWE-266/IntentUriPermissionManipulation.ql
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ ql/java/ql/src/Security/CWE/CWE-200/AndroidSensitiveTextField.ql
ql/java/ql/src/Security/CWE/CWE-200/AndroidWebViewSettingsAllowsContentAccess.ql
ql/java/ql/src/Security/CWE/CWE-200/AndroidWebViewSettingsFileAccess.ql
ql/java/ql/src/Security/CWE/CWE-200/SpringBootActuators.ql
ql/java/ql/src/Security/CWE/CWE-200/SpringBootActuatorsConfig/SpringBootActuatorsConfig.ql
ql/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.ql
ql/java/ql/src/Security/CWE/CWE-209/SensitiveDataExposureThroughErrorMessage.ql
ql/java/ql/src/Security/CWE/CWE-209/StackTraceExposure.ql
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ ql/java/ql/src/Security/CWE/CWE-200/AndroidSensitiveTextField.ql
ql/java/ql/src/Security/CWE/CWE-200/AndroidWebViewSettingsAllowsContentAccess.ql
ql/java/ql/src/Security/CWE/CWE-200/AndroidWebViewSettingsFileAccess.ql
ql/java/ql/src/Security/CWE/CWE-200/SpringBootActuators.ql
ql/java/ql/src/Security/CWE/CWE-200/SpringBootActuatorsConfig/SpringBootActuatorsConfig.ql
ql/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.ql
ql/java/ql/src/Security/CWE/CWE-209/SensitiveDataExposureThroughErrorMessage.ql
ql/java/ql/src/Security/CWE/CWE-209/StackTraceExposure.ql
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,6 @@ ql/java/ql/src/Violations of Best Practice/legacy/ParameterAssignment.ql
ql/java/ql/src/Violations of Best Practice/legacy/UnnecessaryCast.ql
ql/java/ql/src/Violations of Best Practice/legacy/UnnecessaryImport.ql
ql/java/ql/src/definitions.ql
ql/java/ql/src/experimental/Security/CWE/CWE-016/InsecureSpringActuatorConfig.ql
ql/java/ql/src/experimental/Security/CWE/CWE-020/Log4jJndiInjection.ql
ql/java/ql/src/experimental/Security/CWE/CWE-036/OpenStream.ql
ql/java/ql/src/experimental/Security/CWE/CWE-073/FilePathInjection.ql
Expand Down
7 changes: 6 additions & 1 deletion java/ql/lib/semmle/code/configfiles/ConfigFiles.qll
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,12 @@ class ConfigValue extends @configValue, ConfigLocatable {
override string toString() { result = this.getValue() }
}

/** A `.properties` file. */
class PropertiesFile extends File {
PropertiesFile() { this.getExtension() = "properties" }
}

/** A Java property is a name-value pair in a `.properties` file. */
class JavaProperty extends ConfigPair {
JavaProperty() { this.getFile().getExtension() = "properties" }
JavaProperty() { this.getFile() instanceof PropertiesFile }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
/** Provides classes and predicates to reason about Spring Boot actuators exposed in configuration files. */
overlay[local?]
module;

import java
private import semmle.code.configfiles.ConfigFiles
private import semmle.code.xml.MavenPom

/** The parent node of the `org.springframework.boot` group. */
private class SpringBootParent extends Parent {
SpringBootParent() { this.getGroup().getValue() = "org.springframework.boot" }
}

// TODO: private once done with version string debugging in alert msg.
/** A `Pom` with a Spring Boot parent node. */
class SpringBootPom extends Pom {
SpringBootPom() { this.getParentElement() instanceof SpringBootParent }

/** Holds if the Spring Boot Security module is used in the project. */
predicate isSpringBootSecurityUsed() {
this.getADependency().getArtifact().getValue() = "spring-boot-starter-security"
}
}

/** A dependency with artifactId `spring-boot-starter-actuator`. */
class SpringBootStarterActuatorDependency extends Dependency {
SpringBootStarterActuatorDependency() {
this.getArtifact().getValue() = "spring-boot-starter-actuator"
}
}

/** The Spring Boot configuration property `management.security.enabled`. */
private class ManagementSecurityEnabledProperty extends JavaProperty {
ManagementSecurityEnabledProperty() {
this.getNameElement().getName() = "management.security.enabled"
}

/** Gets the whitespace-trimmed value of this property. */
string getValue() { result = this.getValueElement().getValue().trim() }

/** Holds if `management.security.enabled` is set to `false`. */
predicate hasSecurityDisabled() { this.getValue() = "false" }
}

/**
* The Spring Boot configuration property `management.endpoints.web.exposure.include`
* or `management.endpoints.web.expose`.
*/
private class ManagementEndpointsExposeProperty extends JavaProperty {
ManagementEndpointsExposeProperty() {
this.getNameElement().getName() = "management.endpoints.web." + ["exposure.include", "expose"]
}

/** Gets the whitespace-trimmed value of this property. */
string getValue() { result = this.getValueElement().getValue().trim() }
}

private newtype TOption =
TNone() or
TSome(JavaProperty jp)

/**
* An option type that is either a singleton `None` or a `Some` wrapping
* the `JavaProperty` type.
*/
class JavaPropertyOption extends TOption {
/** Gets a textual representation of this element. */
string toString() {
this = TNone() and result = "(none)"
or
result = this.asSome().toString()
}

/** Gets the location of this element. */
Location getLocation() { result = this.asSome().getLocation() }

/** Gets the wrapped element, if any. */
JavaProperty asSome() { this = TSome(result) }

/** Holds if this option is the singleton `None`. */
predicate isNone() { this = TNone() }
}

/**
* Holds if `JavaPropertyOption` jpOption of a repository using `SpringBootStarterActuatorDependency`
* d exposes sensitive Spring Boot Actuator endpoints.
*/
predicate exposesSensitiveEndpoint(
SpringBootStarterActuatorDependency d, JavaPropertyOption jpOption
) {
exists(PropertiesFile propFile, SpringBootPom pom |
d = pom.getADependency() and
not pom.isSpringBootSecurityUsed() and
propFile
.getParentContainer()
.getAbsolutePath()
.matches(pom.getFile().getParentContainer().getAbsolutePath() + "%") and // in the same sub-directory
exists(string springBootVersion |
springBootVersion = pom.getParentElement().getVersionString()
|
springBootVersion.regexpMatch("1\\.[0-4].*") and // version 1.0, 1.1, ..., 1.4
not exists(ManagementSecurityEnabledProperty ep | ep.getFile() = propFile) and
jpOption.isNone()
or
springBootVersion.regexpMatch("1\\.[0-5].*") and // version 1.0, 1.1, ..., 1.5
exists(ManagementSecurityEnabledProperty ep |
ep.hasSecurityDisabled() and ep.getFile() = propFile and ep = jpOption.asSome()
)
or
springBootVersion.matches(["2.%", "3.%"]) and //version 2.x and 3.x
exists(ManagementEndpointsExposeProperty ep |
ep.getFile() = propFile and
ep = jpOption.asSome() and
(
// all endpoints are exposed
ep.getValue() = "*"
or
// version 2.x: exposes health and info only by default
springBootVersion.matches("2.%") and
not ep.getValue() = ["health", "info"]
or
// version 3.x: exposes health only by default
springBootVersion.matches("3.%") and
not ep.getValue() = "health"
)
)
)
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<!DOCTYPE qhelp PUBLIC "-//Semmle//qhelp//EN" "qhelp.dtd">
<qhelp>
<overview>
<p>Spring Boot includes features called actuators that let you monitor and interact with your web
application. Exposing unprotected actuator endpoints through configuration files can lead to
information disclosure or even to remote code execution.</p>
</overview>

<recommendation>
<p>Since actuator endpoints may contain sensitive information, carefully consider when to expose them,
and secure them as you would any sensitive URL. If you need to expose actuator endpoints, use Spring
Security, which secures actuators by default, or define a custom security configuration.
</p>
</recommendation>

<example>
<p>The following examples show <code>application.properties</code> configurations that expose sensitive
actuator endpoints.</p>
<sample src="application_bad.properties" />

<p>The below configurations ensure that sensitive actuator endpoints are not exposed.</p>
<sample src="application_good.properties" />

<p>To use Spring Security, which secures actuators by default, add the <code>spring-boot-starter-security</code>
dependency in your Maven <code>pom.xml</code> file.</p>
<sample src="pom_good.xml" />
</example>

<references>
<li>
Spring Boot Reference Documentation:
<a href="https://docs.spring.io/spring-boot/reference/actuator/endpoints.html">Endpoints</a>.
</li>
<li>
HackerOne Report:
<a href="https://hackerone.com/reports/862589">Spring Actuator endpoints publicly available, leading to account takeover</a>
</li>
</references>
</qhelp>
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/**
* @name Exposed Spring Boot actuators in configuration file
* @description Exposing Spring Boot actuators through configuration files may lead to information leak from
* the internal application, or even to remote code execution.
* @kind problem
* @problem.severity error
* @security-severity 6.5
* @precision high
* @id java/spring-boot-exposed-actuators-config
* @tags security
* external/cwe/cwe-200
*/

import java
import semmle.code.xml.MavenPom
import semmle.code.java.security.SpringBootActuatorsConfigQuery

from SpringBootStarterActuatorDependency d, JavaPropertyOption jpOption, SpringBootPom pom
where
exposesSensitiveEndpoint(d, jpOption) and
// TODO: remove pom; for debugging versions
d = pom.getADependency()
select d,
"Insecure Spring Boot actuator $@ exposes sensitive endpoints (" +
pom.getParentElement().getVersionString() + ").", jpOption, "configuration"
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# vulnerable configuration (Spring Boot 1.0 - 1.4): exposes endpoints by default

# vulnerable configuration (Spring Boot 1.5): false value exposes endpoints
management.security.enabled=false

# vulnerable configuration (Spring Boot 2.x): exposes all endpoints
management.endpoints.web.exposure.include=*

# vulnerable configuration (Spring Boot 3.x): exposes all endpoints
management.endpoints.web.exposure.include=*
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# safe configuration (Spring Boot 1.0 - 1.4)
management.security.enabled=true

# safe configuration (Spring Boot 1.5+)
management.security.enabled=true

# safe configuration (Spring Boot 2.x): exposes health and info only by default
management.endpoints.web.exposure.include=health,info

# safe configuration (Spring Boot 3.x): exposes health only by default
management.endpoints.web.exposure.include=health
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
...
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

<!-- GOOD: Enable Spring Security -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
...
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
category: newQuery
---
* The query `java/insecure-spring-actuator-config` has been promoted from experimental to the main query pack as `java/spring-boot-exposed-actuators-config`. Its results will now appear by default. This query was originally submitted as an experimental query [by @luchua-bc](https://github.com/github/codeql/pull/5384).

This file was deleted.

Loading
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy