flipped-aurora/gin-vue-admin · error

文件名不合法

Error message

文件名不合法

What it means

readSkillFile validates the skill name and file name before joining them into a path under the skill directory. It returns 文件名不合法 when isSafeFileName(fileName) fails, i.e. the file name is blank after trimming, contains '..', contains '/' or '\\', or is not equal to its own filepath.Base. This guards against path traversal when reading skill scripts/resources/references/templates.

Source

Thrown at server/service/system/sys_skills.go:590

		}
		return "", "", fmt.Errorf("%s已存在", label)
	}
	if err := os.MkdirAll(filepath.Dir(filePath), os.ModePerm); err != nil {
		return "", "", err
	}
	content := defaultContent
	if err := os.WriteFile(filePath, []byte(content), 0644); err != nil {
		return "", "", err
	}
	return cleanName, content, nil
}

func (s *SkillsService) readSkillFile(tool, skill, subDir, fileName string) (string, error) {
	if !isSafeName(skill) {
		return "", errors.New("技能名称不合法")
	}
	if !isSafeFileName(fileName) {
		return "", errors.New("文件名不合法")
	}
	skillDir, err := s.skillDir(tool, skill)
	if err != nil {
		return "", err
	}
	filePath := filepath.Join(skillDir, subDir, fileName)
	content, err := os.ReadFile(filePath)
	if err != nil {
		return "", err
	}
	return string(content), nil
}

func (s *SkillsService) writeSkillFile(tool, skill, subDir, fileName, content string) error {
	if !isSafeName(skill) {
		return errors.New("技能名称不合法")
	}
	if !isSafeFileName(fileName) {

View on GitHub (pinned to 3136500ef3)

Solutions

  1. Pass only the bare base file name (no directories, no '..') as fileName.
  2. Trim and validate the file name client-side before calling the API; reject empty or path-containing values.
  3. If a nested file is intended, the API must be extended — readSkillFile only supports files directly in subDir.
  4. Check that the name was not URL-encoded with %2F (%2e%2e is also rejected by the '..' check).

Example fix

// before
svc.GetScript(tool, skill, "scripts", "../other/tool.py")
// after
svc.GetScript(tool, skill, "scripts", "tool.py")
Defensive patterns

Strategy: validation

Validate before calling

func safeFileName(s string) bool {
	t := strings.TrimSpace(s)
	return t != "" && !strings.Contains(t, "..") &&
		!strings.ContainsAny(t, "/\\") && t == filepath.Base(t)
}
if !safeFileName(fileName) { return fmt.Errorf("invalid file name %q", fileName) }

Type guard

func isBareFileName(s string) bool { return s != "" && s == filepath.Base(s) && !strings.ContainsAny(s, "\\/") && !strings.Contains(s, "..") }

Try / catch

name, err := svc.GetScript(tool, skill, subDir, fileName)
if err != nil {
	if strings.Contains(err.Error(), "文件名不合法") {
		// sanitize: keep only filepath.Base, retry once
		fileName = filepath.Base(fileName)
		name, err = svc.GetScript(tool, skill, subDir, fileName)
	}
	if err != nil { return err }
}

Prevention

When it happens

Trigger: Calling GetScript, GetResource, GetReference or GetTemplate with a fileName that is empty/whitespace, includes a subdirectory path (e.g. 'sub/file.py'), contains '..' (e.g. '../../etc/passwd'), or uses backslashes on Linux.

Common situations: Frontend passes a stored relative path including folders instead of the bare file name; user-supplied input contains path separators; attempts to read files outside the skill dir; empty fileName after a string split on '/'.

Related errors


AI-assisted analysis of flipped-aurora/gin-vue-admin@3136500ef3 (2026-08-31). Data as JSON: /api/errors/3d725b83d67690cb. Report an issue: GitHub.