{"record":{"id":"5d5daf8f0f2ef2cc","repo":"MHSanaei/3x-ui","slug":"invalid-filename-contains-unsafe-characters-or-pa","errorCode":null,"errorMessage":"invalid filename: contains unsafe characters or path traversal patterns","messagePattern":"invalid filename: contains unsafe characters or path traversal patterns","errorType":"validation","errorClass":null,"httpStatus":200,"severity":"error","filePath":"internal/web/controller/server.go","lineNumber":260,"sourceCode":"\n// setUpdateChannel toggles whether self-update tracks the rolling dev release.\nfunc (a *ServerController) setUpdateChannel(c *gin.Context) {\n\tdev, err := strconv.ParseBool(c.PostForm(\"dev\"))\n\tif err != nil {\n\t\tjsonMsg(c, \"invalid data\", err)\n\t\treturn\n\t}\n\terr = a.settingService.SetDevChannelEnable(dev)\n\tjsonMsg(c, I18nWeb(c, \"pages.index.updateChannelChanged\"), err)\n}\n\n// updateGeofile updates the specified geo file for Xray.\nfunc (a *ServerController) updateGeofile(c *gin.Context) {\n\tfileName := c.Param(\"fileName\")\n\n\tif fileName != \"\" && !a.serverService.IsValidGeofileName(fileName) {\n\t\tjsonMsg(c, I18nWeb(c, \"pages.index.geofileUpdatePopover\"),\n\t\t\tfmt.Errorf(\"invalid filename: contains unsafe characters or path traversal patterns\"))\n\t\treturn\n\t}\n\n\terr := a.serverService.UpdateGeofile(fileName)\n\tjsonMsg(c, I18nWeb(c, \"pages.index.geofileUpdatePopover\"), err)\n}\n\n// stopXrayService stops the Xray service.\nfunc (a *ServerController) stopXrayService(c *gin.Context) {\n\terr := a.serverService.StopXrayService()\n\tif err != nil {\n\t\tjsonMsg(c, I18nWeb(c, \"pages.xray.stopError\"), err)\n\t\twebsocket.BroadcastXrayState(\"error\", err.Error())\n\t\treturn\n\t}\n\tjsonMsg(c, I18nWeb(c, \"pages.xray.stopSuccess\"), err)\n\twebsocket.BroadcastXrayState(\"stop\", \"\")\n\twebsocket.BroadcastNotification(","sourceCodeStart":242,"sourceCodeEnd":278,"githubUrl":"https://github.com/MHSanaei/3x-ui/blob/ad32144c42455696ea9f14e12168beac3e25f5d2/internal/web/controller/server.go#L242-L278","documentation":"ServerController.updateGeofile passes the user-supplied fileName path parameter through serverService.IsValidGeofileName, a traversal/character guard protecting the geo file download path (files like geosite.dat, geoip.dat under the Xray asset dir). Failure returns the localized popover message plus the detail 'invalid filename: contains unsafe characters or path traversal patterns'. This is a security control — do not bypass it.","triggerScenarios":"POST/GET the geofile update endpoint with fileName containing '../', '..\\\\', absolute paths, slashes, NUL/control bytes, shell metacharacters, or any character outside the allowed geofile-name set.","commonSituations":"Attempting to refresh a custom geo file with a nested path ('custom/geoip.dat'); URL-encoded traversal (%2e%2e%2f) that decodes to '../'; passing an empty-ish or whitespace name; probing the endpoint.","solutions":["Use a plain file name from the allowed set, e.g. geosite.dat, geoip.dat, geosite-ir.dat — no directories, no dots at start.","If you need a custom geo file, place it in the asset folder manually rather than through this endpoint.","Check IsValidGeofileName's implementation in serverService for the exact allowed pattern before automating calls."],"exampleFix":"# before\nGET /panel/api/server/updateGeofile/../x-ui/x-ui.db   # blocked\n\n# after\nGET /panel/api/server/updateGeofile/geosite.dat","handlingStrategy":"validation","validationCode":"var safeGeofile = regexp.MustCompile(`^[A-Za-z0-9][A-Za-z0-9._-]*\\.(dat|mmdb|metadb|db|locoalist|dl)$`) // be conservative; mirror serverService rules\nfunc plausibleGeofileName(name string) bool {\n    return name != \"\" && !strings.Contains(name, \"/\") && !strings.Contains(name, \"\\\\\") && !strings.Contains(name, \"..\") && safeGeofile.MatchString(name)\n}","typeGuard":"function isSafeGeofileName(name: string): boolean {\n  return /^[A-Za-z0-9][A-Za-z0-9._-]*\\.(dat|mmdb|db)$/.test(name) && !name.includes('..')\n}","tryCatchPattern":null,"preventionTips":["Offer geofile names from a fixed dropdown instead of free text.","Never accept directory components in this field.","Remember URL-decoding happens before the check — reject '..' in any encoded form at the edge."],"tags":["api","security","path-traversal","validation","geofile"],"backgroundTag":null,"analyzedSha":"ad32144c42455696ea9f14e12168beac3e25f5d2","analyzedAt":"2026-08-15T11:13:23.905Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}