Tencent/WeKnora · warning
invalid path: %w
Error message
invalid path: %w
What it means
localFileService.SaveFile wraps SafePathUnderBase failures with "invalid path: %w" when the constructed storage directory (baseDir/tenantID/knowledgeID) escapes the configured base directory. SafePathUnderBase canonicalizes both paths and refuses any path not strictly under baseDir, blocking path-traversal uploads. knowledgeID is the main attacker-controlled component.
Source
Thrown at internal/application/service/file/local.go:62
externalURL: strings.TrimRight(externalURL, "/"),
}
}
// SaveFile stores an uploaded file to the local file system
// The file is stored in a directory structure: baseDir/tenantID/knowledgeID/filename
// Returns the full file path or an error if saving fails
func (s *localFileService) SaveFile(ctx context.Context,
file *multipart.FileHeader, tenantID uint64, knowledgeID string,
) (string, error) {
logger.Info(ctx, "Starting to save file locally")
logger.Infof(ctx, "File information: name=%s, size=%d, tenant ID=%d, knowledge ID=%s",
file.Filename, file.Size, tenantID, knowledgeID)
// Create storage directory with tenant and knowledge ID
dir := filepath.Join(s.baseDir, fmt.Sprintf("%d", tenantID), knowledgeID)
if _, err := secutils.SafePathUnderBase(s.baseDir, dir); err != nil {
logger.Errorf(ctx, "Path traversal denied for SaveFile dir: %v", err)
return "", fmt.Errorf("invalid path: %w", err)
}
logger.Infof(ctx, "Creating directory: %s", dir)
if err := os.MkdirAll(dir, 0o755); err != nil {
logger.Errorf(ctx, "Failed to create directory: %v", err)
return "", fmt.Errorf("failed to create directory: %w", err)
}
// Generate unique filename using timestamp
ext := filepath.Ext(file.Filename)
filename := fmt.Sprintf("%d%s", time.Now().UnixNano(), ext)
filePath := filepath.Join(dir, filename)
logger.Infof(ctx, "Generated file path: %s", filePath)
// Open source file for reading
logger.Info(ctx, "Opening source file")
src, err := file.Open()
if err != nil {
logger.Errorf(ctx, "Failed to open source file: %v", err)View on GitHub (pinned to 988cbb0330)
Solutions
- Sanitize knowledgeID before SaveFile: restrict it to a safe charset (UUID/alphanumeric/dash) and reject any value containing "/", "\\", or "..".
- Configure baseDir as a fully-resolved absolute path without symlinks (filepath.EvalSymlinks) so validation and the real layout agree.
- Log the offending knowledgeID and return HTTP 400 — treat as malicious input rather than retrying.
- If IDs must contain separators, map them to a flat safe form (e.g. hash or url-encode) before building the directory.
Example fix
// before
svc.SaveFile(ctx, fh, 1, r.URL.Query().Get("knowledgeId")) // "../../evil"
// after
id := r.URL.Query().Get("knowledgeId")
if !regexp.MustCompile(`^[A-Za-z0-9-]+$`).MatchString(id) {
http.Error(w, "invalid knowledge id", 400); return
}
svc.SaveFile(ctx, fh, 1, id) Defensive patterns
Strategy: validation
Validate before calling
var safeID = regexp.MustCompile(`^[A-Za-z0-9_-]{1,64}$`)
func safeKnowledgeID(id string) bool { return safeID.MatchString(id) } Try / catch
if _, err := svc.SaveFile(ctx, fh, tenantID, knowledgeID); err != nil {
if strings.Contains(err.Error(), "invalid path") {
http.Error(w, "invalid knowledge id", http.StatusBadRequest)
return
}
} Prevention
- Whitelist-validate every path component derived from user input (tenant/knowledge IDs)
- Configure baseDir as an absolute, symlink-free path
- Treat 'invalid path' as a security signal: log and alert on repeated attempts
When it happens
Trigger: SaveFile called with a knowledgeID containing "../", absolute-path segments, or a baseDir that canonicalizes outside itself (e.g. baseDir containing symlinks or relative segments) so that filepath.Join produces a path escaping the base.
Common situations: Client-supplied knowledge ID passed unsanitized from an HTTP handler; knowledge IDs with slashes or dot-dot from a legacy importer; baseDir configured with trailing relative components or symlinked subpaths that resolve outside the base.
Related errors
- invalid file path: %w
- invalid file path: %w
- invalid source path: %w
- member_limit must be >= 0
- missing query parameter
AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02).
Data as JSON: /api/errors/a2ea20f4a865766f.
Report an issue: GitHub.