Build1 publisher3 min readPublished
An exposed Java debug port on a CI server was exploited within hours
Wiz says a TeamCity honeypot exposing JDWP was mining Monero within hours, and GreyNoise counted more than 6,000 unique IPs scanning for the protocol in 90 days.
The Engineer · Build desk
Drafted by a language model from the sources cited here and checked against its claim ledger before publication. How we use AISend a correction
What happened
- The Wiz Research Team observed an exploitation attempt against one of its honeypot servers running TeamCity, a CI/CD tool; investigation determined the attacker gained remote code execution by abusing an exposed Java Debug Wire Protocol (JDWP) interface, ultimately deploying a cryptomining payload and setting up multiple persistence mechanisms.
- Malware was deployed within just a few hours of exposing the vulnerable machine, and Wiz observed this rapid turnaround across multiple attempts.
- JDWP is a standard feature in the Java platform designed to help developers debug live applications, allowing remote inspection of threads, memory and execution flow without restarting the application.
- JDWP does not implement authentication or access control by default, and exposing it to the Internet is considered a misconfiguration.
- When exposed, JDWP becomes a high-risk entry point granting attackers full control over the running Java process; in this case the misconfiguration allowed the adversary to inject and execute arbitrary commands, establish persistence and execute malware.
Compiled by The EngineerSomething wrong?How this is made
Why it matters
Wiz's research team says an exploitation attempt hit one of its honeypot servers running TeamCity, the JetBrains CI/CD product, and that the attacker obtained remote code execution by abusing an exposed Java Debug Wire Protocol interface before deploying a cryptomining payload and multiple persistence mechanisms [1]. The timing is the part operators should act on: Wiz reports the malware arrived within a few hours of the machine being exposed, and that it saw the same turnaround across multiple attempts [2].
JDWP is a standard feature of the Java platform, built so developers can inspect threads, memory and execution flow in a live application without restarting it [3]. It implements no authentication or access control by default [4]. Exposure therefore hands an attacker full control over the running Java process, which in Wiz's incident was enough to inject and execute arbitrary commands, establish persistence and run malware [5].
The sequence Wiz describes has no CVE in it. The attacker scanned for open JDWP ports, reached the honeypot on port 5005, and sent a JDWP-Handshake to confirm the interface was live [6]. The JVM replied with version details and a list of loaded classes [7]. From there, according to Wiz, the actor followed a structured path to code execution, probably using a variant of the public tool jdwp-shellifier with extra features [8]: query the JVM for classes and methods, locate java.lang.Runtime along with getRuntime() and exec() [9], then build Java strings containing system commands and invoke them through INVOKESTATICMETHOD_SIG and INVOKEMETHOD_SIG [10]. That is the protocol doing its job. There is nothing to patch.
Which is why this belongs on the build desk rather than the appsec desk. The flag developers use tells the JVM to listen for debugger connections on port 5005 and accept them on all interfaces [11]. Wiz lists TeamCity, Jenkins, Selenium Grid, Elasticsearch, Quarkus, Spring Boot and Apache Tomcat among the applications that may start a JDWP server when run in debug mode [12], often without making the risk obvious to the developer [13]. Debug mode in a container image, a CI agent template or a troubleshooting session that never got reverted is the same misconfiguration as an intentional internet-facing debugger.
Scanning volume supports the speed. Using GreyNoise tag-based search, Wiz found more than 6,000 unique IP addresses probing for JDWP endpoints over the previous 90 days [14], an average of roughly 67 new scanning addresses a day [15].
The payload was built to survive a look. Wiz says the attacker used a modified XMRig with a hardcoded configuration, avoiding the suspicious command-line arguments defenders tend to flag [16], and routed through mining pool proxies to hide the wallet address so investigators could not pivot on it [17].
Caveats worth keeping: this is one vendor's honeypot telemetry, and Wiz notes it observed multiple JDWP exploitation attempts from different actors and wrote up a single representative incident, with the published indicators covering all the activity rather than that one case [18].
What to watch: whether 5005 and other agentlib listeners appear in your own egress and ingress data, whether debug flags are baked into base images and agent definitions, and whether the workloads exposed this way stay limited to mining. The access described here is control of the running process [5], and on a build server that process is the one holding the credentials.