CVE-2026-34581
Description
goshs is a SimpleHTTPServer written in Go. From version 1.1.0 to before version 2.0.0-beta.2, when using the Share Token it is possible to bypass the limited selected file download with all the gosh functionalities, including code exec. This issue has been patched in version 2.0.0-beta.2.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
github.com/patrickhener/goshsGo | >= 1.1.0 | — |
Affected products
2Patches
16fb224ed15c2Fix webdav bug and address https://github.com/patrickhener/goshs/security/advisories/GHSA-jgfx-74g2-9r6g, a security bug where token can be used to bypass authentication and upload,delete files and run cli commands, if the module is activated. The attacker would need a valid share token beforehand.
4 files changed · +52 −5
httpserver/handler.go+35 −3 modified@@ -103,28 +103,46 @@ func (fs *FileServer) doFile(file *os.File, w http.ResponseWriter, req *http.Req func (fs *FileServer) earlyBreakParameters(w http.ResponseWriter, req *http.Request) bool { if _, ok := req.URL.Query()["smtp"]; ok { + if denyForTokenAccess(w, req) { + return true + } fs.handleSMTPAttachment(w, req) return true } if _, ok := req.URL.Query()["goshs-info"]; ok { + if denyForTokenAccess(w, req) { + return true + } fs.handleInfo(w) return true } if _, ok := req.URL.Query()["mkdir"]; ok { + if denyForTokenAccess(w, req) { + return true + } fs.handleMkdir(w, req) return true } if _, ok := req.URL.Query()["ws"]; ok { + if denyForTokenAccess(w, req) { + return true + } fs.socket(w, req) return true } if _, ok := req.URL.Query()["cbDown"]; ok { + if denyForTokenAccess(w, req) { + return true + } if !fs.NoClipboard && !fs.Invisible { fs.cbDown(w, req) return true } } if _, ok := req.URL.Query()["bulk"]; ok { + if denyForTokenAccess(w, req) { + return true + } if !fs.Invisible { fs.bulkDownload(w, req) } else { @@ -133,6 +151,9 @@ func (fs *FileServer) earlyBreakParameters(w http.ResponseWriter, req *http.Requ return true } if _, ok := req.URL.Query()["static"]; ok { + if denyForTokenAccess(w, req) { + return true + } if !fs.Invisible { fs.static(w, req) } else { @@ -141,6 +162,9 @@ func (fs *FileServer) earlyBreakParameters(w http.ResponseWriter, req *http.Requ return true } if _, ok := req.URL.Query()["embedded"]; ok { + if denyForTokenAccess(w, req) { + return true + } if err := fs.embedded(w, req); err != nil { if !fs.Invisible { body := fs.emitCollabEvent(req, http.StatusNotFound) @@ -155,6 +179,9 @@ func (fs *FileServer) earlyBreakParameters(w http.ResponseWriter, req *http.Requ return true } if _, ok := req.URL.Query()["delete"]; ok { + if denyForTokenAccess(w, req) { + return true + } if !fs.ReadOnly && !fs.UploadOnly && !fs.NoDelete { fs.deleteFile(w, req) return true @@ -164,6 +191,9 @@ func (fs *FileServer) earlyBreakParameters(w http.ResponseWriter, req *http.Requ } } if _, ok := req.URL.Query()["share"]; ok { + if denyForTokenAccess(w, req) { + return true + } if !fs.Invisible { fs.CreateShareHandler(w, req) } else { @@ -836,9 +866,11 @@ func (fs *FileServer) ShareHandler(w http.ResponseWriter, r *http.Request) { entry.Downloaded++ fs.SharedLinks[token] = entry - if fs.SharedLinks[token].Downloaded >= fs.SharedLinks[token].DownloadLimit { - // Remove the share link from map to keep it clean - delete(fs.SharedLinks, token) + if fs.SharedLinks[token].DownloadLimit != -1 { + if fs.SharedLinks[token].Downloaded >= fs.SharedLinks[token].DownloadLimit { + // Remove the share link from map to keep it clean + delete(fs.SharedLinks, token) + } } }
httpserver/helper.go+8 −0 modified@@ -77,3 +77,11 @@ func GenerateQRCode(uri string) string { return fmt.Sprintf("data:image/png;base64,%s", encoded) } + +func denyForTokenAccess(w http.ResponseWriter, r *http.Request) bool { + if r.URL.Query().Get("token") != "" { + http.Error(w, "Forbidden", http.StatusForbidden) + return true + } + return false +}
httpserver/server.go+6 −0 modified@@ -93,13 +93,19 @@ func (fs *FileServer) SetupMux(mux *CustomMux, what string) string { // Define routes mux.HandleFunc("POST /", func(w http.ResponseWriter, r *http.Request) { if strings.HasSuffix(r.URL.Path, "/upload") { + if denyForTokenAccess(w, r) { + return + } fs.upload(w, r) runtime.GC() } else { fs.logOnly(w, r) } }) mux.HandleFunc("PUT /", func(w http.ResponseWriter, r *http.Request) { + if denyForTokenAccess(w, r) { + return + } fs.put(w, r) }) mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
server/server.go+3 −2 modified@@ -28,8 +28,9 @@ func StartAll(opts *options.Options) { // webdav if opts.WebDav { - httpSrv.Port = opts.WebDavPort - go httpSrv.Start("webdav") + webdavSrv := httpserver.NewHttpServer(opts, hub, clip, wl, *wh) + webdavSrv.WebdavPort = opts.WebDavPort + go webdavSrv.Start("webdav") } if opts.SFTP {
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
5- github.com/patrickhener/goshs/commit/6fb224ed15c2ccc0c61a5ebe22f2401eb06e9216nvdPatchWEB
- github.com/patrickhener/goshs/security/advisories/GHSA-jgfx-74g2-9r6gnvdExploitVendor AdvisoryWEB
- github.com/advisories/GHSA-jgfx-74g2-9r6gghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2026-34581ghsaADVISORY
- github.com/patrickhener/goshs/releases/tag/v2.0.0-beta.2nvdProductRelease NotesWEB
News mentions
0No linked articles in our index yet.