Apr 19, 2026·8 min read·3 visits
A path traversal flaw in the Wish SCP middleware allows arbitrary file read and write operations outside the designated root directory via crafted SCP requests.
A critical path traversal vulnerability in the SCP middleware of the Wish Go library (GHSA-xjvp-7243-rg9h) permits attackers to read and write arbitrary files outside the configured root directory. The flaw originates from insufficient path sanitization in the `fileSystemHandler.prefixed()` method, enabling severe impacts including remote code execution if critical system files are overwritten. Exploitation requires authentication unless the target server explicitly runs without authentication protocols.
The Wish framework is a Go library used by developers to build custom SSH servers, providing various middleware components to handle specific protocols. The SCP middleware within this library is designed to facilitate secure file transfers over SSH. A critical vulnerability, tracked as GHSA-xjvp-7243-rg9h, exists within this SCP middleware implementation, specifically concerning how file paths are validated against a designated root directory.
This flaw is classified as CWE-22: Improper Limitation of a Pathname to a Restricted Directory. The vulnerability manifests when the SCP middleware processes incoming file transfer requests. By supplying a pathname containing specific traversal sequences, an attacker can coerce the server into resolving paths outside the intended filesystem boundary.
The vulnerability enables three distinct attack vectors: arbitrary file write, arbitrary file read, and file enumeration. An authenticated malicious SCP client can leverage these vectors to interact with any file on the host system, constrained only by the operating system permissions granted to the process running the Wish SSH server. If the server is configured without authentication, the attack can be executed entirely unauthenticated.
The severity of this issue is reflected in its CVSS v3.1 score of 9.6 (Critical). The vulnerability represents a fundamental failure in input validation at the protocol handling layer. Custom SSH servers utilizing the affected middleware are directly exposed to complete system compromise if an attacker overwrites critical execution components such as scheduled tasks or authorized SSH keys.
The vulnerability stems from the implementation of the fileSystemHandler.prefixed() method located in scp/filesystem.go. This method is responsible for restricting all file operations to a developer-configured root directory. The intended logic attempts to sanitize user-provided paths and append them to the root path safely.
The logic relies primarily on the filepath.Clean(path) function from the Go standard library to resolve relative components such as ../. The method correctly strips redundant separators and resolves relative path segments internally. The subsequent logic assumes that filepath.Clean is sufficient to prevent path traversal when combined with filepath.Join.
The fundamental error occurs because filepath.Clean processes the provided string independently, without the context of the intended base directory. If a user provides a path containing excessive ../ segments, such as ../../../etc/passwd, filepath.Clean will retain those relative segments if it interprets the path as absolute or rootless. When filepath.Join(h.root, path) is subsequently called, the Go standard library interprets the ../ segments and traverses upward from h.root.
Because the resulting joined path is not verified to ensure it still resides within h.root, the application blindly trusts the output of filepath.Join. This architectural assumption that standard library path cleansing inherently provides security boundary confinement directly enables the path traversal capability.
The implementation of the vulnerable path resolution logic highlights the failure to enforce boundary confinement after string manipulation. The original implementation attempts to optimize path checking but creates a dangerous bypass.
func (h *fileSystemHandler) prefixed(path string) string {
path = filepath.Clean(path)
if strings.HasPrefix(path, h.root) {
return path
}
return filepath.Join(h.root, path)
}In the vulnerable code block above, if an attacker supplies path as ../../../tmp/pwned, filepath.Clean returns ../../../tmp/pwned. The strings.HasPrefix check fails, and the code executes filepath.Join(h.root, "../../../tmp/pwned"). If h.root is /var/lib/ssh, the resulting path becomes /tmp/pwned. The application returns this unauthorized path directly to the calling file operation function.
func (h *fileSystemHandler) prefixed(path string) (string, error) {
joined := filepath.Join(h.root, filepath.Clean("/"+path))
if !strings.HasPrefix(joined, h.root+string(filepath.Separator)) && joined != h.root {
return "", fmt.Errorf("path traversal detected")
}
return joined, nil
}The patched code fundamentally changes the validation strategy. It modifies the signature to return an error, enabling strict rejection of invalid paths. The code ensures all user input is treated as an absolute path contextually by prepending / before invoking filepath.Clean. This forces Clean to resolve and discard leading ../ segments entirely.
Furthermore, the patch implements a robust post-resolution boundary check. By validating that the fully resolved joined string possesses the exact h.root prefix followed by an explicit filepath.Separator, the application ensures the targeted file definitively resides within the intended directory hierarchy.
Exploitation requires direct interaction with the Wish SSH server utilizing standard or custom SCP client implementations. The Arbitrary File Write attack, triggered during the scp -t (receive) operation, occurs because the server utilizes regular expressions to capture incoming filenames from the SCP protocol header. These regex routines fail to sanitize path separators, passing strings containing ../ directly to Mkdir() or Write().
The provided Proof-of-Concept demonstrates establishing an SSH session and sending a malicious SCP protocol header. The Go program waits for the server's initialization acknowledgment, then injects a forged C0644 file creation command containing the traversal payload ../../../tmp/pwned.
// Connect to the vulnerable server (e.g., target:2222)
client, _ := gossh.Dial("tcp", "target:2222", config)
session, _ := client.NewSession()
stdin, _ := session.StdinPipe()
go func() {
// Wait for server's NULL ack
buf := make([]byte, 1)
session.Stdout.Read(buf)
// Send crafted SCP header with traversal payload
fmt.Fprintf(stdin, "C0644 12 ../../../tmp/pwned\n")
stdin.Write([]byte("hello world\n"))
stdin.Write([]byte{0}) // NULL terminator
stdin.Close()
}()
session.Run("scp -t .")The Arbitrary File Read vulnerability relies on the scp -f (send) command. The server explicitly extracts the file path from the SSH command arguments provided by the client. An attacker executes scp -f ../../../etc/passwd, causing the prefixed() method to miscalculate the path, resolving the system password database and returning its contents to the client.
Additionally, the file enumeration vector exploits the Glob method within the filesystem handler. The handler passes user-controlled strings containing wildcard characters directly to filepath.Glob subsequent to the flawed prefixed() calculation. This allows an attacker to recursively list directories outside the configured root, mapping the underlying host filesystem structure.
The exploitation of this vulnerability severely compromises the integrity, confidentiality, and availability of the host system. The Arbitrary File Write capability allows attackers to place executable payloads, overwrite sensitive configuration files, or modify authorization mechanisms. Writing a public key to /root/.ssh/authorized_keys or a malicious script to /etc/cron.d/ directly leads to unauthenticated Remote Code Execution.
The Arbitrary File Read vector breaks the confidentiality guarantees of the SSH service. Attackers can extract application source code, sensitive environment variables, private cryptographic keys, and user credential databases such as /etc/shadow. This information facilitates lateral movement and privilege escalation across the network environment.
The CVSS vector CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:N accurately represents the threat profile. The Network attack vector (AV:N) and Low complexity (AC:L) indicate straightforward remote exploitation. The Scope is Changed (S:C) because the vulnerability within the Wish middleware explicitly grants unauthorized control over the underlying operating system environment.
The precise impact scales depending on the execution context of the Go binary hosting the Wish SSH server. If the application is executed as the root user, full system compromise is instantaneous. If the application executes within a deeply locked down container or under an unprivileged service account, the impact is isolated to the permissions of that specific identity.
The primary remediation for GHSA-xjvp-7243-rg9h is upgrading the affected dependencies within the custom SSH application. Developers using the charm.land/wish/v2 module must update their go.mod file to depend on version 2.0.1 or later. Applications utilizing the deprecated github.com/charmbracelet/wish v1 codebase are inherently vulnerable; maintainers must migrate entirely to the v2 ecosystem to receive the security patch.
If immediate dependency updates are not feasible, temporary mitigation strategies must be applied. Developers should explicitly remove or disable the SCP middleware component from the Wish server initialization if the file transfer functionality is not strictly required. Replacing SCP with more modern, robust protocols like SFTP, which are handled by separate middleware modules, reduces the exposure surface.
System administrators deploying custom Wish servers must apply Defense-in-Depth principles to restrict application capabilities. Running the Go binary under an unprivileged service user using standard Linux permissions prevents an attacker from overwriting critical system files. Deploying the application within a read-only containerized environment or applying strict AppArmor and SELinux profiles substantially curtails the lateral movement potential following exploitation.
Monitoring and detection controls should be configured to identify exploitation attempts. SSH audit logs should capture the execution of scp commands. Security Information and Event Management (SIEM) systems should alert on SCP command arguments containing multiple ../ sequences or targeting known sensitive directories such as /etc, /root, or /var/log.
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
charm.land/wish/v2 Charmbracelet | <= 2.0.0 | 2.0.1 |
github.com/charmbracelet/wish Charmbracelet | <= 1.4.7 | None |
| Attribute | Detail |
|---|---|
| Advisory ID | GHSA-xjvp-7243-rg9h |
| CVSS Score | 9.6 |
| Attack Vector | Network |
| CWE ID | CWE-22 |
| Impact | Arbitrary File Read/Write |
| Exploit Status | Proof-of-Concept Available |
The software uses external input to construct a pathname that is intended to identify a file or directory that is located underneath a restricted parent directory, but the software does not properly neutralize special elements within the pathname that can cause the pathname to resolve to a location that is outside of the restricted directory.