CVE-2025-46816: Goshs! Your Simple HTTP Server Just Became an Open Backdoor
TL;DR / Executive Summary
CVE-2025-46816 exposes a critical Remote Code Execution (RCE) vulnerability in goshs
, a Go-based simple HTTP server, affecting versions 0.3.4 through 1.0.4. When goshs
is run without specific command-line arguments (like the -c
flag to explicitly enable command execution), it inadvertently leaves a WebSocket endpoint open for unauthenticated command execution. Attackers can send a crafted WebSocket message to run arbitrary commands on the server with the server process's privileges. The vulnerability carries a high severity. Users should immediately upgrade to goshs
version 1.0.5 or later, which correctly checks if command execution via WebSockets is permitted based on server startup flags. If an upgrade isn't possible, ensure goshs
is not exposed to untrusted networks or run with restrictive configurations.
Introduction
Imagine setting up a quick, 'harmless' HTTP server for some local file sharing or a rapid development task. You type goshs
in your terminal and hit enter. Job done, right? You've got a server running. Wrong! If you were using goshs
versions 0.3.4 to 1.0.4, you might have just unknowingly rolled out the red carpet for attackers.
Today, we're dissecting CVE-2025-46816, a sneaky vulnerability that turns this handy Go Simple HTTP Server (goshs
) into an unwilling accomplice for remote command execution. This isn't just about one tool; it's a stark reminder that even the simplest utilities, especially network-facing ones, need robust security considerations from the ground up. For developers, sysadmins, and security professionals, this CVE is a compelling case study in how default configurations and unchecked features can lead to significant, and often surprising, compromise. Why should you care? Because a tool designed for convenience accidentally became a gateway for control.
Technical Deep Dive
Vulnerability Details: The Open Door
At its heart, CVE-2025-46816 is an unauthenticated Remote Code Execution (RCE) vulnerability. goshs
includes a feature allowing command execution via WebSockets. This functionality is intended to be explicitly enabled by the user through the -c
(or --cli
) command-line flag when starting the server. However, in the vulnerable versions (0.3.4 to 1.0.4), the server doesn't actually verify if this flag was provided when it receives a command execution request over a WebSocket connection. If goshs
is started without any arguments, it defaults to a state where this WebSocket command channel is dangerously receptive.
Root Cause Analysis: The Missing Checkpoint
The core of the issue lies within the dispatchReadPump
function, located in ws/client.go
. This function is responsible for handling incoming messages from connected WebSocket clients. When a specially crafted JSON message like {"type": "command", "content": "your_malicious_command_here"}
arrives, the vulnerable code proceeds to unmarshal the content
and execute it as a system command. Crucially, it does this without first checking if the server was actually started with the -c
flag that's supposed to authorize this very behavior.
Think of it like a high-tech club with a special VIP room (command execution). The bouncer (the dispatchReadPump
function) is supposed to check for a specific VIP pass (the -c
flag) before letting anyone into that room. However, in this case, the bouncer just lets anyone in who walks up to the WebSocket entrance and says, "I'd like to execute a command," completely forgetting to check if the club owner (the user who started goshs
) ever authorized VIP access in the first place.
Here's a simplified representation of the vulnerable logic:
// ws/client.go (Simplified vulnerable logic before patch)
func (c *Client) dispatchReadPump(packet Packet) {
switch packet.Type {
// ... other cases for clipboard, etc.
case "command":
var command string
// Assumes packet.Content is a JSON string for the command
if err := json.Unmarshal(packet.Content, &command); err != nil {
logger.Errorf("Error reading json packet: %+v", err)
// Potentially continues or breaks, but the check is missing
}
logger.Debugf("Command was: %+v", command)
// PROBLEM: No check here to see if command execution is allowed by server config!
// It just goes ahead and runs the command.
output, err := cli.RunCMD(command) // Executes the command
if err != nil {
logger.Errorf("Error running command: %+v", err)
}
logger.Debugf("Output: %+v", output)
c.updateCLI(output) // Sends output back over WebSocket
default:
logger.Warnf("The event sent via websocket cannot be handeled: %+v", packet.Type)
}
}
Attack Vectors: How They Get In
An attacker who can reach the goshs
instance over the network can connect to its WebSocket endpoint (typically ws://<server_ip>:8000/?ws
). By sending a simple JSON payload, they can execute arbitrary commands with the same privileges as the goshs
process. This is particularly dangerous if goshs
is inadvertently run as root (a terrible practice, but it happens!) or by a user with significant privileges. The attack doesn't require any authentication β just network access to the goshs
port.
Business Impact: Why It's Bad News
The impact of CVE-2025-46816 is severe, potentially leading to full server compromise:
- Data Theft: Attackers can access, modify, or exfiltrate any files readable by the
goshs
process. - Server Hijacking: The compromised server can be used for nefarious activities like participating in DDoS attacks, mining cryptocurrency, or hosting malicious content.
- Lateral Movement: The server can become a pivot point for attackers to move deeper into the internal network.
- Full System Compromise: If
goshs
runs with high privileges (e.g., root), the entire system is at risk. - Reputational Damage: For any organization unknowingly exposing this vulnerability, the damage to trust and reputation can be significant.
Proof of Concept (PoC)
Seeing is believing, and exploiting this vulnerability is alarmingly simple. The discoverer provided a straightforward PoC using websocat
, a versatile command-line WebSocket client.
Scenario: Your vulnerable goshs
server (version 0.3.4-1.0.4) is running on 192.168.1.11:8000
. Importantly, it was started simply by typing goshs
without any arguments, making it vulnerable by default.
Attack Command:
# PoC using websocat to execute the 'id' command on the server
echo -e '{"type": "command", "content": "id"}' | websocat 'ws://192.168.1.11:8000/?ws' -t
Expected Output (if vulnerable):
The server will execute the id
command, and its output will be sent back through the WebSocket. You'll see something like:
{"type":"cli","content":"uid=1000(youruser) gid=1000(youruser) groups=1000(youruser),4(adm),24(cdrom)...\n"}
This confirms successful command execution. An attacker could replace "id"
with any other command, such as ls -la
to list files, or far more destructive commands. (Please, only test this on systems you own and have permission to test on!)
Mitigation and Remediation
Don't panic, but do act! Here's how to protect yourself from CVE-2025-46816:
Immediate Fixes:
- Upgrade
goshs
(Recommended): The primary and most effective solution is to upgrade togoshs
version 1.0.5 or later. This version contains the patch that fixes the vulnerability.
You can typically upgrade using Go's toolchain:
Alternatively, download the latest pre-compiled binary from the goshs releases page.go install github.com/patrickhener/goshs@latest # or go get -u github.com/patrickhener/goshs if using older Go versions in GOPATH mode
- Restrict Access: If upgrading immediately isn't feasible (though it really should be a priority):
- Ensure
goshs
is not exposed to untrusted networks. - Use a firewall to limit access strictly to trusted IP addresses.
- If only local access is needed, bind
goshs
to localhost:goshs -i 127.0.0.1
.
- Ensure
- Explicitly Disable CLI (if not upgrading): If you must use a vulnerable version and do not need command execution, ensure you are not running it with default arguments if those defaults are insecure. However, the vulnerability lies in it being enabled even when not explicitly requested. The safest bet is to upgrade.
Long-Term Solutions:
- Principle of Least Privilege: Always run services like
goshs
with the minimum necessary permissions. Avoid running it as root. - Secure Defaults: For developers creating tools: ensure your applications have secure defaults. Features with significant security implications (like RCE) should be opt-in and rigorously checked, not opt-out or accidentally enabled.
Verification Steps:
After upgrading to goshs
1.0.5 or later:
- Start
goshs
without any arguments (the previously vulnerable scenario):goshs
- Attempt the PoC command again:
echo -e '{"type": "command", "content": "id"}' | websocat 'ws://<your_server_ip>:8000/?ws' -t
- You should not see the output of the
id
command. The WebSocket connection might still establish, but the server should ignore the "command" request because command execution wasn't enabled via the-c
flag. This confirms the fix is working.
Patch Analysis: Behind the Scenes of the Fix
The fix implemented in goshs
version 1.0.5 is straightforward and directly addresses the root cause by ensuring the server's startup configuration is respected. Let's peek at the key changes (diffs simplified for clarity):
-
Making the Hub Aware (
httpserver/server.go
&ws/hub.go
):- The
Hub
struct (which manages WebSocket connections) inws/hub.go
now includes acliEnabled bool
field. This field will store whether command-line execution was permitted at startup.// File: ws/hub.go type Hub struct { // ... other fields (clients, broadcast, register, unregister, cb) + // CLI Enabled + cliEnabled bool } // NewHub will create a new hub -func NewHub(cb *clipboard.Clipboard) *Hub { +func NewHub(cb *clipboard.Clipboard, cliEnabled bool) *Hub { // cliEnabled is passed in return &Hub{ // ... other initializations cb: cb, + cliEnabled: cliEnabled, // Store the flag } }
- In
httpserver/server.go
, when theFileServer
initializes the WebSocketHub
, it now passes itsCLI
configuration (which knows if the-c
flag was used).
(Note: The actual// File: httpserver/server.go func (fs *FileServer) Start(what string) { // ... // init websocket hub - fs.Hub = ws.NewHub(fs.Clipboard) + fs.Hub = ws.NewHub(fs.Clipboard, fs.CLI) // fs.CLI now passes its state }
fs.CLI
being passed might be a boolean derived from the CLI options, e.g.,fs.CLIOptions.Command
, rather than the whole struct, but the principle is that the hub now knows the intended state.)
- The
-
The Decisive Check (
ws/client.go
):- The
dispatchReadPump
function inws/client.go
, which processes incoming WebSocket messages, now crucially checks thec.hub.cliEnabled
flag before attempting to execute any command.// File: ws/client.go func (c *Client) dispatchReadPump(packet Packet) { // ... case "command": + if c.hub.cliEnabled { // <-- THE CRITICAL FIX! var command string if err := json.Unmarshal(packet.Content, &command); err != nil { logger.Errorf("Error reading json packet: %+v", err) // Potentially return or break } logger.Debugf("Command was: %+v", command) output, err := cli.RunCMD(command) if err != nil { logger.Errorf("Error running command: %+v", err) } logger.Debugf("Output: %+v", output) c.updateCLI(output) + } // else, if cliEnabled is false, this "command" packet is effectively ignored. // ... }
- The
Why the fix works: The patch ensures that the WebSocket command processing logic respects the server's initial configuration. If goshs
wasn't started with the -c
flag (or any other mechanism that would set cliEnabled
to true
), then c.hub.cliEnabled
will be false
. Consequently, the entire block of code responsible for unmarshalling and executing the command is skipped. Our bouncer is now diligently checking for that VIP pass!
Timeline
- Vulnerable Code Introduced: With
goshs
version 0.3.4 (when the WebSocket command function was added). - Discovery Date: Not publicly specified in the advisory beyond its presence since v0.3.4.
- Vendor Notification: Not publicly specified. The fix commit
160220974576afe5111485b8d12fd36058984cfa
was made by the project maintainer,patrickhener
. - Patch Commit Date: The primary fix was included in commit
160220974576afe5111485b8d12fd36058984cfa
. (GitHub shows this commit was made on Oct 29, 2023). - Patched Version Release (1.0.5): Tagged and released, incorporating the fix. The advisory indicates 1.0.5 as the first patched version.
- Public Disclosure (GHSA-rwj2-w85g-5cmm & CVE-2025-46816): May 6, 2025.
Lessons Learned
This vulnerability, CVE-2025-46816, in goshs
offers several valuable lessons:
-
Prevention Practices:
- Secure by Default: This is paramount. Features with significant security implications, like remote command execution, should always be opt-in and disabled by default. Never assume users will run software only in perfectly secure, isolated environments.
- Explicit Authorization Checks: Every privileged operation must explicitly verify that the requestor is authorized AND that the server is configured to allow such an operation. It's not enough to receive a "command" request; the system must check if it should process it.
- Configuration Awareness: Ensure that runtime behavior (like handling WebSocket messages) is directly and correctly influenced by initial configuration settings, especially security-critical ones.
-
Detection Techniques:
- Network Monitoring: Keep an eye on network traffic. Unexpected WebSocket connections or unusual traffic patterns to
goshs
instances (or any simple server) should raise suspicion, especially if you aren't intentionally using WebSocket features. - Endpoint Detection and Response (EDR): Monitor for anomalous process creation. If
goshs
(or a similar lightweight server) suddenly starts spawning shell processes (bash
,sh
,powershell
,cmd.exe
), it's a massive red flag indicating potential compromise. - Log Analysis: Regularly review application and server logs for errors, warnings, or debug messages that might indicate attempted or successful exploitation (e.g., "Error running command" if an attacker tries a malformed command).
- Network Monitoring: Keep an eye on network traffic. Unexpected WebSocket connections or unusual traffic patterns to
-
One Key Takeaway: Defaults dictate destiny (for security). A simple oversight in how default behavior is handled can transform a useful utility into a gaping security hole. Always scrutinize default configurations, especially for network-facing services, and champion the principle of "secure by default" in your own development practices.
References and Further Reading
- Official GitHub Advisory: GHSA-rwj2-w85g-5cmm
goshs
Repository: https://github.com/patrickhener/goshsgoshs
Patch Commit: 160220974576afe5111485b8d12fd36058984cfawebsocat
(PoC Tool): https://github.com/vi/websocat
So, the next time you spin up a "simple" server or use a utility that offers powerful features, take a moment to ask: what are its defaults, and could they be an open invitation rather than a locked door? Stay vigilant, patch promptly, and question defaults!