Published · 6d agoBuild8 min read
The debug port your CI opens on purpose: JDWP, Selenium Grid and threats no patch closes
Wiz reports exposed Java debug interfaces exploited within hours and an active cryptomining campaign in Selenium Grid. Both are documented features reachable from the internet, not defects.
Written for builders.See today for builders

What happened
- Wiz Research observed an exploitation attempt against one of its honeypot servers running TeamCity, a popular CI/CD tool; the attacker gained remote code execution by abusing an exposed Java Debug Wire Protocol (JDWP) interface, deploying a cryptomining payload and setting up multiple persistence mechanisms.
- The attacker scanned for open JDWP ports across the internet; one scan reached the honeypot exposing JDWP on port 5005. A JDWP-Handshake request confirmed the interface was active, and the JVM responded with version details and a list of loaded classes.
- JDWP does not implement authentication or access control by default, and exposing it to the internet is considered a misconfiguration; when exposed it grants attackers full control over the running Java process.
- To enable JDWP, developers typically start the JVM with a flag that tells the JVM to listen for debugger connections on port 5005 and accept incoming connections on all interfaces.
- Malware was deployed within just a few hours of exposing the vulnerable machine, and Wiz observed this rapid turnaround across multiple attempts.
Compiled by The EngineerSomething wrong?How this is made
Why it matters
Wiz Research says it watched an attacker take remote code execution on a honeypot running TeamCity by talking to an exposed Java Debug Wire Protocol interface, then deploy a cryptomining payload and several persistence mechanisms [1]. The same team has separately documented an ongoing campaign it calls SeleniumGreed, which mines cryptocurrency on internet-reachable Selenium Grid services and was still running as of publication [14]. Both threats land on the same class of asset: machines you run headless, in a build or test fleet, that nobody logs into and nobody watches. Neither is closed by patching, because in neither case is anything broken.
The protocol is doing exactly what it documents
Start with what JDWP is for. Oracle's own architecture specification describes it as the format of debugging information and requests between a debuggee and a debugger, where requests originate on the debugger side and include queries for information, setting of state changes in the remote VM, and setting of debugging state [12]. Changing the state of a remote virtual machine is the product. The back-end that answers those requests is not a third-party add-on either: in the reference implementation it is a native shared library shipped with the JDK [13].
So the intrusion Wiz describes reads like an API walkthrough rather than an exploit. The attacker scanned for open JDWP ports, reached a honeypot listening on 5005, sent a handshake, and the JVM replied with version details and a list of loaded classes [2]. From there the sequence was structured and, according to Wiz, probably a variant of the public jdwp-shellifier tool: enumerate classes and methods, locate java.lang.Runtime with its getRuntime() and exec() methods, build Java strings containing system commands, and invoke them through the protocol's own method-invocation messages [7]. There is no memory corruption in that chain and no version-specific gadget. JDWP simply implements no authentication or access control by default, which is why Wiz classifies exposing it to the internet as a misconfiguration that grants an attacker full control over the running Java process [3].
Selenium Grid has the same shape. Its WebDriver API allows full interaction with the machine itself, including reading and downloading files and running remote commands, and authentication is not enabled by default because the service was designed for internal networks [15][16]. The Selenium project said as much in its own response to the Wiz report: Grid ships without authentication because the assumption has always been that operators put it behind a secure network [23]. Two threats, two default-open control planes, no software defect between them [2].
The documented path to a real deployment is a path to open ports
This is where the mechanism gets uncomfortable, because the exposure is not produced by carelessness alone. It is produced by following the instructions.
Selenium's own getting-started documentation shows standalone mode listening for WebDriver requests on localhost:4444, and names as a common use case an easy-to-set-up Grid inside a CI/CD tool such as GitHub Actions or Jenkins [26]. Standalone, however, can only run on one machine, and the reason most teams adopt hub-and-node is to combine machines with different operating systems and browser versions [29]. Making that work requires opening ports: the documentation states that to register a node to a hub you must expose the Event Bus ports, 4442 and 4443 by default, on the hub machine, and the node port as well [27]. Distributed mode, where each component runs on its own machine, adds 5557 to the Event Bus set [28]. The supported route from a single-box convenience to a real grid therefore names four distinct listening ports to open on hosts that, in a cloud account, frequently have public addresses attached [3].
JDWP is worse in one specific respect. The flag developers typically use to turn it on tells the JVM to listen for debugger connections on port 5005 and to accept incoming connections on all interfaces [4]. Selenium standalone at least starts bound to localhost [26]; the common JDWP recipe starts bound to everything [4]. And the enabling is often not a deliberate act at all. Wiz notes that JDWP is not on by default in most Java applications but that many popular ones start a JDWP server automatically when run in debug mode, frequently without making the risk obvious, listing TeamCity, Jenkins, Selenium Grid, Elasticsearch, Quarkus, Spring Boot and Apache Tomcat [10]. Read that list next to Selenium's CI use case and the overlap is the point: the machines that auto-start a debug listener in debug mode are the build servers, the test grids and the search nodes, which is the same inventory as the Selenium exposure [6].
The exposure window is measured in hours, not weeks
The usual defence of a temporarily open debug port is that it will not be open long. The numbers do not support that. Wiz reports that malware was deployed within a few hours of exposing the vulnerable machine, and that it saw the same rapid turnaround across multiple attempts [5]. Using GreyNoise's tag-based search, it counted more than 6,000 unique IP addresses scanning for JDWP endpoints over 90 days [6], and during its own investigation it observed JDWP exploitation attempts from several different actors [11]. That is a market, not a single crew. For Selenium, Wiz believes its report is the first documentation of this misconfiguration being exploited in the wild [19], which tells you something about how long a class of exposure can sit in plain sight before anyone writes it down.
Scale explains the interest. Wiz's data puts Selenium in more than 30% of cloud environments as the most common testing framework, and the official selenium/hub Docker image has been pulled over 100 million times, averaging more than 150,000 pulls a week [20][21]. A weekly six-figure pull rate means the population of these services is continuously replaced, so a fix applied to a fleet today is not a fix applied to the images someone deploys next week.
The payloads are built against your detections
Both campaigns run a modified XMRig, and both spend effort on staying un-pivotable. On the JDWP incident the miner carried a hardcoded configuration specifically so it would not need suspicious command-line arguments of the kind defenders flag, and it used mining pool proxies to hide the wallet address and prevent investigators pivoting on it [8][9]. SeleniumGreed used a modified XMRig packed with custom UPX headers, delivered by running Python with a reverse shell through the WebDriver API, and used other compromised Selenium nodes as command-and-control for hosting payloads and as a mining pool proxy [17][18]. The common ground is not the coin, it is the anti-attribution: hardcoded configs defeat command-line detection, and proxies defeat wallet-based clustering [1].
Two consequences follow for anyone running these fleets. First, indicator lists built from pool proxies decay quickly, because the proxies are other victims' machines [18]. Second, a compromised test node is not only a cost line, it is delivery infrastructure aimed at the next victim [18]. And the hiding place is well chosen: Grid exists to distribute test execution across nodes so that a large suite finishes faster [22], so sustained heavy CPU on a node is the machine doing its job [5].
Where upgrading still helps, and where there is nothing to upgrade to
The sources are not identical on the value of patching, and the difference is worth stating rather than smoothing over. Wiz treats exposed JDWP as a misconfiguration rather than a vulnerability [3], which means there is no version to move to; the only lever is who can reach port 5005. The Selenium project takes a more nuanced line on its own software: the abuse works on most versions, but a lot of the observed effort goes into Selenium Grid 3.14, and it asks users to upgrade because security items have been added since then [24]. It also points to concrete steps, including running the server's own `info security` output and, as an alternative, running Grid at a cloud provider [25]. So upgrading raises the floor for Selenium. It does not change the default, which remains no authentication and an assumed network boundary [23].
That distinction is why this class of threat sits awkwardly beside the industry's current preoccupation. In marketing for a webinar on AI-assisted coding, ActiveState says it surveyed 300 security and engineering leaders across technology, financial services, healthcare, manufacturing and government, and that its research quantifies the acceleration of remediation backlogs and maps that to liability and business outcomes [30]. Its framing is that AI coding tools have become a rapidly growing source of unvetted open source in production, leaving teams with packages they did not approve and vulnerabilities they do not know how to prioritise [31]; its speakers, Rebecca Banks and Moris Chen, are billed as discussing which approaches mitigate remediation burden and which merely redistribute it [32]. Take the framing at face value and the asymmetry is obvious. Package debt is a queue with a prioritisation problem, and prioritisation problems absorb unlimited attention. A reachable control plane has no queue and no prioritisation question. The port either answers strangers or it does not.
What to watch
The useful audit is not a scan of your dependency manifests, it is a list of what your build and test hosts answer to from outside your network: 5005 for JDWP [4], 4444 for Grid [26], 4442, 4443 and 5557 for the Event Bus [27][28]. Check whether any of your images run applications in debug mode, since that is what starts a JDWP listener without asking [10], and look at the Selenium server's own `info security` output before deciding your grid is fine [25]. If you find a compromised node, treat it as having potentially hosted payloads and proxied traffic for other victims, not just as a mining cost [18]. And watch whether the governance conversation that ActiveState is convening around AI-generated code [30] ever reaches configuration reachability, because the two active campaigns described here would not appear in any package inventory.
Claim ledger
Ranked by verification strength, evidence, and original report placement.
- [1]
Wiz Research observed an exploitation attempt against one of its honeypot servers running TeamCity, a popular CI/CD tool; the attacker gained remote code execution by abusing an exposed Java Debug Wire Protocol (JDWP) interface, deploying a cryptomining payload and setting up multiple persistence mechanisms.
- [2]
The attacker scanned for open JDWP ports across the internet; one scan reached the honeypot exposing JDWP on port 5005. A JDWP-Handshake request confirmed the interface was active, and the JVM responded with version details and a list of loaded classes.
- [3]
JDWP does not implement authentication or access control by default, and exposing it to the internet is considered a misconfiguration; when exposed it grants attackers full control over the running Java process.
- [4]
To enable JDWP, developers typically start the JVM with a flag that tells the JVM to listen for debugger connections on port 5005 and accept incoming connections on all interfaces.
- [5]
Malware was deployed within just a few hours of exposing the vulnerable machine, and Wiz observed this rapid turnaround across multiple attempts.
- [6]
Using GreyNoise's tag-based search feature, Wiz found over 6,000 unique IP addresses scanning for JDWP endpoints in the past 90 days.
Sources & coverage · 4 publishers
The reporting this story was synthesized from, earliest first. Every link goes to the original.
- thehacker.newsAug 15Shipping 10–50× More Code? Learn How to Keep Security in Control
Cited in this coverage: ActiveState webinar promotion published by thehacker.news
- wiz.io6d agoExposed JDWP Exploited in the Wild | Wiz Blog
- docs.oracle.com6d agoJava Platform Debugger Architecture

