flipped-aurora/gin-vue-admin · warning
技能名称不合法
Error message
技能名称不合法
What it means
SkillsService.Detail validates the skill name with isSafeName before resolving its directory on disk. A name failing this check (empty, path separators, traversal like ../, or other unsafe characters) is rejected with this error to prevent path traversal outside the skills root.
Source
Thrown at server/service/system/sys_skills.go:92
}
entries, err := os.ReadDir(skillsDir)
if err != nil {
return nil, err
}
var skills []string
for _, entry := range entries {
if entry.IsDir() {
skills = append(skills, entry.Name())
}
}
sort.Strings(skills)
return skills, nil
}
func (s *SkillsService) Detail(_ context.Context, tool, skill string) (system.SkillDetail, error) {
var detail system.SkillDetail
if !isSafeName(skill) {
return detail, errors.New("技能名称不合法")
}
detail.Tool = tool
detail.Skill = skill
skillDir, err := s.skillDir(tool, skill)
if err != nil {
return detail, err
}
skillFilePath := filepath.Join(skillDir, skillFileName)
content, err := os.ReadFile(skillFilePath)
if err != nil {
if !os.IsNotExist(err) {
return detail, err
}
detail.Meta = system.SkillMeta{Name: skill}
detail.Markdown = defaultSkillMarkdown
} else {View on GitHub (pinned to 3136500ef3)
Solutions
- Pass only the bare skill directory name, without path separators or '..' segments.
- Trim and re-validate the skill value on the client before sending the request.
- If the name legitimately needs normalization, sanitize it server-side before calling Detail.
Example fix
// before detail, err := skillsService.Detail(ctx, "claude", "../../etc") // after detail, err := skillsService.Detail(ctx, "claude", "my-skill")
Defensive patterns
Strategy: validation
Validate before calling
const safeNameRe = /^[A-Za-z0-9][A-Za-z0-9._-]*$/
if !safeNameRe.test(skill) throw new Error("invalid skill name: " + skill)
await api.getSkillDetail(tool, skill) Type guard
func isSafeSkillName(s string) bool {
if s == "" { return false }
if strings.ContainsAny(s, "/\\") { return false }
return !strings.Contains(s, "..")
} Try / catch
try {
await api.getSkillDetail(tool, skill)
} catch (e) {
if (e.response?.data?.msg === "技能名称不合法") {
showInputError("技能名称只能包含字母、数字、点、下划线和中划线")
}
} Prevention
- Always send bare skill names from server-provided list data, never user-typed paths.
- Normalize/trim input before sending.
- Reject names with separators or '..' client-side for immediate feedback.
When it happens
Trigger: Calling Detail(tool, skill) with a skill value that is empty or contains '/', '\\', '..', or other characters rejected by isSafeName.
Common situations: Client sends a skill name copied from a file path (e.g. 'skills/my-skill/SKILL.md'); crafted URLs attempting directory traversal; frontend sends empty skill param after a bad selection.
Related errors
AI-assisted analysis of flipped-aurora/gin-vue-admin@3136500ef3 (2026-08-31).
Data as JSON: /api/errors/97d68aedfe0245b2.
Report an issue: GitHub.