Stealing Secrets Using Spring Actuators: Spring Actuator Security Part 1

Are you looking for effective ways to secure your Spring applications? Look no further! Our very own Dr. Ing. Max Maass has created a comprehensive 3-part series on Spring Actuator Security, covering everything from identifying vulnerabilities to implementing best practices. From safeguarding your app to protecting your sensitive data, we've got you covered. Join us as we delve into the world of Spring Actuator Security and learn how to keep your applications safe and secure.

Spring is a set of frameworks for developing Applications in Java. It is widely used, and so it is not unusual to encounter it during a security audit or penetration test. One of its features that I recently encountered during a whitebox audit is actuators. In this series of articles, I will use them as a case study for security testing.

In the first part I'll be using them to describe the risk involved in exposing actuators to the Internet by demonstrating how they can be used to steal secrets from your applications, using a basic Spring application as a case study.

In the next parts of the series, I will discuss how to detect the misconfiguration using static code analysis and dynamic testing, and finally, how you can secure those actuators that you absolutely cannot leave turned off.

Part 1: Stealing Secrets Using Spring Actuators

  1. What are Actuators?
  2. Exploiting Public Actuators
  3. Exposing the Environment
    3.1 Reading Logs
    3.2 Changing Log Configuration
    3.3 Actually, I'll just have Everything to Go, Please
  4. Closing Notes


1. What are Actuators?

Actuators expose information about the running Spring application via (amongst others) a REST API and can be used to retrieve data from the system, or even make configuration changes if configured (in)correctly. They can be quite helpful in debugging or monitoring a Spring application, but if you expose them too widely, things can get dangerous very quickly.

By default, only the health check endpoint is enabled over REST, listening at /actuator/health. However, it is possible to enable additional endpoints, for example to expose metrics to Prometheus for monitoring. This can be done through settings in the relevant .properties file (or its YAML equivalent):

It is also possible to enable all endpoints for access over REST, by using the following setting in the relevant .properties file:


This is the config that I found during a recent engagement - and since the application was explicitly configured to expose all actuators without any authentication, I was curious to see what other actuators exist, and how they could be leveraged to attack the application. The result was this article series (and a call to the customer, telling them to make some changes to their configuration right now).

2. Exploiting Public Actuators

Conveniently, Spring provides a list of all actuators that are present by default and can be enabled. They include actuators for reading (and writing!) the log configuration, the application environment (including environment variables), and even the logs of the application. Even more conveniently, by default, it will show you the list of enabled actuators if you simply access /actuator, removing the guesswork out of determining which actuators you have to work with.

I've created a basic, vulnerable Spring application that exposes all endpoints, if you want to follow along at home. Running it locally on your machine and accessing the Spring actuators endpoint, you will get the following output:

basic vulnerable Spring application

There have been some articles about exploiting actuators, which can even lead to remote code execution (RCE) on the machine running the application. Veracode discussed a series of paths to RCE in 2019 (although some of their methods no longer work on modern Spring versions). In this article, I wanted to highlight a few additional endpoints that can prove dangerous, to illustrate why you should be careful with this feature.


3. Exposing the Environment

Let's assume the application you are running is using environmental variables to pull in configuration values:

environmental variables to pull in configuration values

One of the endpoints allows us to take a peek at the application environment. Let's see if we can get these tokens using the env actuator:

So, we can read the DB connection string in plaintext from the actuator. Sweet. What about the AWS credentials? Well, the situation is a bit more complicated here:

As you can see, the data is being redacted. Spring automatically tries to redact sensitive values in the Actuator output, based on the name of the environment variable. If we had been more careless and chosen a different name, the data would be right here for the taking, but sadly, Spring has prevented us from trivially stealing the values here. But, there are of course other ways to achieve this goal.


3.1. Reading Logs

Let's assume that your application has the following code:

Reading Logs

Assuming it is configured to log to a file, Spring helpfully exposes an endpoint called /actuator/logfile. Let's take a look at what this can give us:

actuator logfile

And there we go - we can pull the AWS credentials right from the logs.

This is, admittedly, a bit far-fetched. No one in their right mind would log AWS credentials in a production environment, right? Okay, then let's make a few changes to the code to reflect this:

actuator logfile changed

So you build, deploy, double-check that the logs are clean, and go to bed, knowing that your application is now safe - right?


3.2. Changing Log Configuration

Enter /actuator/loggers. This endpoint gives us the log configuration for the application, and looks something like this:

Changing Log Configuration

So, we can see that the logger is configured to only log on the INFO level. Sure, this isn't great (the endpoint discloses a lot about the structure of the application, used dependencies, etc.), but it isn't immediately dangerous. What is dangerous is the fact that the logger configuration can also be changed from this actuator by sending a POST to the correct endpoint. In this case, I am setting the loglevel for the logger com.example.demo.DemoApplication to DEBUG:

com.example.demo.DemoApplication to DEBUG

Visit the page again, retrieve the logs - and there we go:

retrieving the logs

The logs are back, clearly showing that the application is now logging on the DEBUG level. Now you are seriously annoyed, and decide to do what you should have done before: get rid of the logging statement, as there really is no good reason for it to be there in the first place anyway.

application is now logging on the DEBUG level

Build, deploy, and finally we're safe. Right?


3.3. Actually, I'll Just Have Everything To Go, Please

Pulling data from logs is a really tedious task, and there is no guarantee for me (as an attacker) that the application will actually log interesting things. Sure, I could go ahead and set every single external library to the TRACE loglevel, collect the logs, and sift through them, but really, this seems like a lot of work I'd rather avoid doing, thank you very much. Why go to that trouble if I could instead just take... everything?

Well, lucky for me, there is /actuator/heapdump. This endpoint does exactly what it sounds like - it takes a copy of the Java heap (i.e., the memory of the application) and provides it to me as a large blob of binary data. Let's grab a copy and dig in.


Now, since you have cleverly disabled the logging of AWS credentials, I can no longer just read them from the logs - but they are still in the heap of the application! Likely in the middle of a big chunk of meaningless binary data, but that's what the strings utility is for - it pulls sequences of printable characters from any file and presents them to you, newline-separated. You can then just pipe the whole thing through grep to find what you are looking for. For example, AWS credentials.


And there we go - secrets, pulled directly from the brain of your application. In the same way, we could pull out cryptographic keys, API credentials, user data that the application is currently working on, internal API addresses, AWS resource identifiers, or whatever else the application is using. And at this point, there really isn't anything you can do about it.

Well, except, of course, not exposing your actuators.


4. Closing Notes

I've only gone through a small number of the actuators in this blog post, and these aren't even necessarily the most dangerous ones. The only arguably harmless endpoint is the health check actuator (which is also the only one that is enabled by default). Any other endpoint should be considered dangerous (yes, even the Prometheus endpoint you are using for monitoring your application, unless you are fine with showing the whole world your resource usage and whatever business metrics you are exposing through it). The best thing you can do it to turn off every endpoint you are not actively using, limit access to the others using the firewall, and add authentication requirements.

In the next parts of this blog series, I will discuss how to detect your exposed endpoints.

We will begin with detecting them in your code, and then move on to detecting them with dynamic security scanners. Finally, we will discuss how you can secure your actuators against attackers.

Further reading:

I would like to thank Jannik Hollenbach for his helpful feedback on an early version of this article. In addition, I would like to thank the Security Community at my employer, iteratec, for their input on this issue.



Max Maas – Security Expert at iteratec. I break your software before other people do, and then help you secure it afterwards :)

Dieser Blogbeitrag erschien ursprünglich auf:

Mehr Infos und weitere interessante Beiträge unter:

Tags: Software, Technology