During my research, I had discovered a high-severity zero day in the Red Hat build of Quarkus — a popular, full-stack, Kubernetes-native Java framework optimized for Java virtual machines (JVMs) and native compilation that’s used as a platform for serverless, cloud and Kubernetes environments.
I was hoping it would be announced in time for the talk, but it was a week too late. Given that Red Hat published details of the vulnerability — CVE-2022-4116 — on Monday, Nov. 21, I can now share details of the vulnerability, which is a dangerous one.
At this point, the vulnerability has been rated 9.8 on the CVSS v3 Base Score. The vulnerability is found in the Dev UI Config Editor, which is vulnerable to drive-by localhost attacks that could lead to remote-code execution (RCE). Exploiting the vulnerability isn’t difficult and can be done by a malicious actor without any privileges.
The payload I created — see here and here on GitHub — just opens the system calculator. However, the potential exists for the silent code to take more damaging actions such as installing a keylogger on the local machine to capture login information to production systems, or using GitHub tokens to modify source code.
The above HTML is hosted on joebeeton.github.io along with example vulnerable codebases.
The nature of the beast
As I explained in my DeepSec talk, there is a widespread belief that services that are only bound to localhost are not accessible from the outside world. Because of this misplaced belief, developers, for the sake of convenience, will run services they are developing that are configured in a less secure way compared with how they would (hopefully!) do it.
However, there are certain types of requests, called Simple Requests, that do not require a preflight request. According to Mozilla, such requests have to be either GET, HEAD or POST Requests.
Also, the request can only have a Content type of:
- text/plain, or
- No content type.
Within those constraints, it is possible to access localhost and, in certain circumstances, to trigger arbitrary code execution.
As developers have write access to codebases, AWS keys, server creds, etc., access to the developer's machine gives an attacker a great deal of scope to pivot to other resources on the network, as well as to modify or to flat-out steal the codebase.
We’re not sure how extensively the Red Hat build of Quarkus is used. Having been started only in 2019, the Quarkus framework is still young, and the Spring Boot framework is said to be far more popular.
But it’s worth noting that Quarkus is reportedly getting more popular, particularly in Kubernetes use cases, given its ease of use and significantly lighter demand on hardware resources to run and to run applications.
Still, it’s probably safe to assume that the use of Quarkus isn’t extensive, considering that it’s focused on Kubernetes usage. While many developers use Kubernetes, not all are using Quarkus. Therefore, the number of developers affected by this drive-by localhost attack is probably small.
During the development process of a Quarkus application, a developer would normally run the service being developed on their own machine. Quarkus has a nice feature, called Developer Mode, to help.
I started by using:
This allows background compilation and live reload as the developer modifies the application, as well as the ability to modify configuration settings via a Web UI.
The Dev UI allows for live modification of the application’s configuration.
Changes to this UI modify the application.properties within the project and trigger a live reload of the application.
The Dev UI is designed to only be used during the development process of the application and only bound to localhost. Because of this, there is no authentication or other security controls built into it, such as a Cross-Site Request Forgery (CSRF) token.
Properties in the Dev UI are modified using a POST request with content type of application/x-www-form-urlencoded.
Making the POST request modifies the property and reloads the application. Also, as it’s a POST request with a content type of application/x-www-form-urlencoded, it is a simple request.
- What is the impact of modifying Quarkus properties?
Getting developers to access the malicious website
Some ways that attackers could lure Quarkus users might include:
One way to get people using Quarkus to visit your website would be to build a tutorial website for Quarkus. Some of those reading would be following along with the tutorial and would either already have Quarkus running or would start it up as they go through the tutorial.
Impact of modifying properties
If an attacker is able to modify the properties of a Quarkus application, they’re capable of creating an RCE vulnerability on the target system. There are likely several ways of doing this. Once an adversary is able to modify the properties of an application, escalating to RCE is almost a certainty.
The easiest way I’ve found to craft such an attack is based on work done by security researcher and white-hat hacker Eugene Lim.
The proof of concept (POC):
The above POC does the following.
- The POST request modifies the JDBC URL of this application.
- That modification changes the H2 database to have an argument of
INIT=runscript from ‘’
- As the Quarkus application is reloaded, the H2 database is rebuilt, and the in-memory H2 database pulls down the exec.sql script and executes it.
ALIAScommand to compile a Java method that runs whatever command is passed in.
- The next line in the SQL script calls that method with the argument open
/System/Applications/Calculator.app, thus opening the calculator app on the target’s machine.
The fix implemented by the Quarkus team for CVE-2022-4116 — which is in versions 2.14.2.Final and 2.13.5.Final (LTS) — requires the Dev UI to check the origin header so that it only accepts requests that contain a header of:
origin : localhost
origin : example.com
Drive-by localhost attacks as an attack vector against developers
The underlying issue here is that the Quarkus team assumed that, since the service was designed to only be run on a developer’s local machine and bound to localhost, it would be safe from attacks originating on the internet. Therefore, they did not add any security controls. However, this class of attack vector is not limited to Quarkus. I have found similar issues in other web services that are normally left open when bound to localhost. There are likely to be many more.
Attack payloads for Quarkus and other frameworks can be found here.
An attack vector with a limited shelf life
While CVE-2022-4116 has been fixed, there are likely many more equivalent vulnerabilities in other frameworks. Luckily, there is a solution on the horizon that should block this attack vector without finding and fixing each vulnerable framework: W3C’s new Private Network Access specification.
This specification splits the hosts into three areas:
- Public internet
- Private network
When a request is made in the browser from a less private network to a more private one, even Simple Requests trigger a preflight.
Also, a new CORS header is added to the preflight request of:
The server will need to respond with a header of:
Access-Control-Allow-Private-Network : true
… for the browser to then allow the actual POST/GET etc. request through.
If the server does not respond with the above header set to true, the request is blocked. For this class of attack to work with this specification, the server would have to specifically opt in to allow requests that originate from less private networks. This effectively blocks this attack vector for those browsers that support it.
Browser support for Private Network Access
Currently, only the team behind the Chromium/Chrome browser is actively working on implementing the new specification, which is currently scheduled for Chrome 109, due to be released mid-December 2022.
Firefox has Private Network Access on its backlog, but a release date has not yet been scheduled. I’ve not been able to find information on Safari or Edge. Given that Edge is Chromium-based, the browser may get Private Network Access at some point as the change in Chromium feeds into Edge.