{"record":{"id":"92e0e3b68329681e","repo":"Tencent/WeKnora","slug":"path-q-is-not-a-valid-file-path","errorCode":null,"errorMessage":"path %q is not a valid file path","messagePattern":"path %q is not a valid file path","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"internal/agent/tools/skill_file.go","lineNumber":398,"sourceCode":"// resolveSkillFilePath turns a model-supplied path into an absolute path\n// proven to sit inside skillDir.\n//\n// A relative path is resolved against skillDir, which is what the model\n// reaches for after being told the directory once. Everything is then cleaned\n// and re-checked against the prefix, so \"..\", a symlink-looking spelling or an\n// absolute path into a neighbouring skill all fail here rather than reaching\n// the image. The directory itself is refused: it is not a file.\nfunc resolveSkillFilePath(skillDir, requested string) (string, error) {\n\tdir := path.Clean(strings.TrimSpace(skillDir))\n\tif dir == \"\" || dir == \".\" || dir == \"/\" {\n\t\treturn \"\", fmt.Errorf(\"this tool is not bound to a skill directory\")\n\t}\n\ttrimmed := strings.TrimSpace(requested)\n\tif trimmed == \"\" {\n\t\treturn \"\", fmt.Errorf(\"path is required; write a file inside %s\", dir)\n\t}\n\tif strings.ContainsRune(trimmed, 0) {\n\t\treturn \"\", fmt.Errorf(\"path %q is not a valid file path\", requested)\n\t}\n\tcandidate := trimmed\n\tif !path.IsAbs(candidate) {\n\t\tcandidate = path.Join(dir, candidate)\n\t}\n\tclean := path.Clean(candidate)\n\tif clean == dir || !strings.HasPrefix(clean, dir+\"/\") {\n\t\treturn \"\", fmt.Errorf(\n\t\t\t\"path %q is outside this install's skill directory (%s); \"+\n\t\t\t\t\"an install may only write its own skill\",\n\t\t\trequested, dir,\n\t\t)\n\t}\n\treturn clean, nil\n}\n","sourceCodeStart":380,"sourceCodeEnd":414,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/agent/tools/skill_file.go#L380-L414","documentation":"resolveSkillFilePath rejects a requested path containing a NUL byte (strings.ContainsRune(trimmed, 0)), since NUL is illegal in filesystem paths and typically signals corrupt or injected input. The error echoes the original requested path quoted for debugging.","triggerScenarios":"Calling Execute with a path argument that embeds a \"\\x00\" character, usually from binary/corrupt data or deliberate path-traversal probing rather than normal model output.","commonSituations":"Adversarial prompt injection attempting filesystem tricks; binary payloads accidentally concatenated into a path string; upstream decoding bugs producing NUL-terminated C-string artifacts.","solutions":["Strip or reject NUL bytes from the path before calling Execute.","Sanitize model-provided paths with a whitelist of allowed characters.","Log and flag the request as suspicious if NUL bytes appear, since it likely indicates injection."],"exampleFix":"// before\np := strings.ReplaceAll(rawPath, \"\\x00\", \"\") // silently kept going, or passed raw\n// after\nif strings.ContainsRune(rawPath, 0) {\n    return errors.New(\"path contains NUL byte; rejecting\")\n}\nin := SkillFileInput{Path: rawPath, Content: content}","handlingStrategy":"validation","validationCode":"if strings.ContainsRune(input.Path, 0) {\n    return errors.New(\"path contains NUL byte; rejecting input\")\n}","typeGuard":"func isCleanPath(p string) bool { return !strings.ContainsRune(p, 0) && strings.TrimSpace(p) != \"\" }","tryCatchPattern":"if _, err := tool.Execute(ctx, input); err != nil && strings.Contains(err.Error(), \"not a valid file path\") {\n    // sanitize or drop the request; treat as suspicious input\n}","preventionTips":["Sanitize all model-provided paths against a character whitelist","Treat NUL bytes as an injection signal and log/alert on them","Avoid building paths from binary or C-string data without decoding checks"],"tags":["path-safety","security","validation"],"backgroundTag":"invalid-path-characters","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}