MHSanaei/3x-ui · error

invalid filename: contains unsafe characters or path travers

Error message

invalid filename: contains unsafe characters or path traversal patterns

What it means

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.

Source

Thrown at internal/web/controller/server.go:260

// setUpdateChannel toggles whether self-update tracks the rolling dev release.
func (a *ServerController) setUpdateChannel(c *gin.Context) {
	dev, err := strconv.ParseBool(c.PostForm("dev"))
	if err != nil {
		jsonMsg(c, "invalid data", err)
		return
	}
	err = a.settingService.SetDevChannelEnable(dev)
	jsonMsg(c, I18nWeb(c, "pages.index.updateChannelChanged"), err)
}

// updateGeofile updates the specified geo file for Xray.
func (a *ServerController) updateGeofile(c *gin.Context) {
	fileName := c.Param("fileName")

	if fileName != "" && !a.serverService.IsValidGeofileName(fileName) {
		jsonMsg(c, I18nWeb(c, "pages.index.geofileUpdatePopover"),
			fmt.Errorf("invalid filename: contains unsafe characters or path traversal patterns"))
		return
	}

	err := a.serverService.UpdateGeofile(fileName)
	jsonMsg(c, I18nWeb(c, "pages.index.geofileUpdatePopover"), err)
}

// stopXrayService stops the Xray service.
func (a *ServerController) stopXrayService(c *gin.Context) {
	err := a.serverService.StopXrayService()
	if err != nil {
		jsonMsg(c, I18nWeb(c, "pages.xray.stopError"), err)
		websocket.BroadcastXrayState("error", err.Error())
		return
	}
	jsonMsg(c, I18nWeb(c, "pages.xray.stopSuccess"), err)
	websocket.BroadcastXrayState("stop", "")
	websocket.BroadcastNotification(

View on GitHub (pinned to ad32144c42)

Solutions

  1. Use a plain file name from the allowed set, e.g. geosite.dat, geoip.dat, geosite-ir.dat — no directories, no dots at start.
  2. If you need a custom geo file, place it in the asset folder manually rather than through this endpoint.
  3. Check IsValidGeofileName's implementation in serverService for the exact allowed pattern before automating calls.

Example fix

# before
GET /panel/api/server/updateGeofile/../x-ui/x-ui.db   # blocked

# after
GET /panel/api/server/updateGeofile/geosite.dat
Defensive patterns

Strategy: validation

Validate before calling

var safeGeofile = regexp.MustCompile(`^[A-Za-z0-9][A-Za-z0-9._-]*\.(dat|mmdb|metadb|db|locoalist|dl)$`) // be conservative; mirror serverService rules
func plausibleGeofileName(name string) bool {
    return name != "" && !strings.Contains(name, "/") && !strings.Contains(name, "\\") && !strings.Contains(name, "..") && safeGeofile.MatchString(name)
}

Type guard

function isSafeGeofileName(name: string): boolean {
  return /^[A-Za-z0-9][A-Za-z0-9._-]*\.(dat|mmdb|db)$/.test(name) && !name.includes('..')
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of MHSanaei/3x-ui@ad32144c42 (2026-08-15). Data as JSON: /api/errors/5d5daf8f0f2ef2cc. Report an issue: GitHub.