{"record":{"id":"eb12f588e79e4a08","repo":"Tencent/WeKnora","slug":"invalid-file-path-w-eb12f5","errorCode":null,"errorMessage":"invalid file path: %w","messagePattern":"invalid file path: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/application/service/file/oss.go","lineNumber":289,"sourceCode":"\t\tSourceKey:    oss.Ptr(srcKey),\n\t})\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to copy file in OSS: %w\", err)\n\t}\n\n\tnewPath := fmt.Sprintf(\"oss://%s/%s\", s.bucketName, destKey)\n\tlogger.Infof(ctx, \"Copied OSS object %s to %s\", srcPath, newPath)\n\treturn newPath, nil\n}\n\n// GetFile retrieves a file from OSS by its path.\nfunc (s *ossFileService) GetFile(ctx context.Context, filePath string) (io.ReadCloser, error) {\n\tbucketName, objectName, err := parseOssFilePath(filePath)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif err := utils.SafeObjectKey(objectName); err != nil {\n\t\treturn nil, fmt.Errorf(\"invalid file path: %w\", err)\n\t}\n\n\tvar client *oss.Client\n\tif bucketName == s.tempBucketName && s.tempClient != nil {\n\t\tclient = s.tempClient\n\t} else {\n\t\tclient = s.client\n\t}\n\n\tresp, err := client.GetObject(ctx, &oss.GetObjectRequest{\n\t\tBucket: oss.Ptr(bucketName),\n\t\tKey:    oss.Ptr(objectName),\n\t})\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to get file from OSS: %w\", err)\n\t}\n\n\treturn resp.Body, nil","sourceCodeStart":271,"sourceCodeEnd":307,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/application/service/file/oss.go#L271-L307","documentation":"This error is returned by ossFileService.GetFile when utils.SafeObjectKey rejects the object key parsed from filePath. Parsing succeeded (the path is a valid oss:// URL), but the key content is unsafe — typically path traversal or illegal characters. It is a security guard executed before GetObject, protecting against reading unintended objects.","triggerScenarios":"Calling GetFile with an oss:// path whose object key contains traversal sequences (../), leading slashes, or other characters rejected by utils.SafeObjectKey.","commonSituations":"File paths built from user input in download endpoints; legacy DB records with unnormalized keys; attackers probing for path traversal to read other tenants' objects.","solutions":["Reject the request and log the offending path — never attempt to silently sanitize and proceed.","Validate keys with utils.SafeObjectKey at write/ingest time so only safe keys are ever stored.","Generate object keys server-side (UUID-based, as SaveFile does) instead of accepting client-supplied keys.","Scope tenantID into the key prefix and validate it as part of authorization."],"exampleFix":"// before\nreader, err := svc.GetFile(ctx, fmt.Sprintf(\"oss://%s/%s\", bucket, userKey))\n// after\nif err := utils.SafeObjectKey(userKey); err != nil {\n    return nil, fmt.Errorf(\"unsafe object key: %w\", err)\n}\nreader, err := svc.GetFile(ctx, fmt.Sprintf(\"oss://%s/%s\", bucket, userKey))","handlingStrategy":"validation","validationCode":"_, key, err := parseOssFilePath(filePath)\nif err != nil { return err }\nif err := utils.SafeObjectKey(key); err != nil {\n    return fmt.Errorf(\"unsafe key: %w\", err)\n}","typeGuard":"func isSafeOSSPath(p string) bool {\n    _, key, err := parseOssFilePath(p)\n    return err == nil && utils.SafeObjectKey(key) == nil\n}","tryCatchPattern":"reader, err := svc.GetFile(ctx, filePath)\nif err != nil {\n    if strings.Contains(err.Error(), \"invalid file path\") {\n        return errBadPath // 400-level client error, never retry\n    }\n    return err\n}","preventionTips":["Reject unsafe keys at the API boundary instead of at storage time.","Generate object keys server-side (UUID-based).","Scope keys under a tenantID prefix and verify it during authorization.","Never interpolate user input directly into oss:// paths.","Add fuzz/edge-case tests to SafeObjectKey."],"tags":["oss","download","validation","path-traversal","security"],"backgroundTag":"unsafe-object-key","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}