{"record":{"id":"62c72ca6415ba043","repo":"flipped-aurora/gin-vue-admin","slug":"error-62c72c","errorCode":null,"errorMessage":"日志文件路径不合法","messagePattern":"日志文件路径不合法","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/service/system/sys_log_viewer.go","lineNumber":31,"sourceCode":"\t\"sort\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/flipped-aurora/gin-vue-admin/server/global\"\n\tsystemReq \"github.com/flipped-aurora/gin-vue-admin/server/model/system/request\"\n\tsystemRes \"github.com/flipped-aurora/gin-vue-admin/server/model/system/response\"\n)\n\nconst (\n\tDefaultLogChunkLines = 500\n\tMaxLogChunkBytes     = 2 * 1024 * 1024\n\tlogReadBlockSize     = 64 * 1024\n)\n\nvar (\n\tErrInvalidLogMonth    = errors.New(\"日志月份格式不正确\")\n\tErrInvalidLogDate     = errors.New(\"日志日期格式不正确\")\n\tErrInvalidLogPath     = errors.New(\"日志文件路径不合法\")\n\tErrLogFileNotFound    = errors.New(\"日志文件不存在\")\n\tErrLogFileUnreadable  = errors.New(\"日志文件不可读取\")\n\tErrLogRootUnavailable = errors.New(\"日志目录不可读取\")\n)\n\ntype LogViewerService struct{}\n\nfunc (s *LogViewerService) ListDates(ctx context.Context, month string) (result systemRes.LogDateList, err error) {\n\tresult = systemRes.LogDateList{Month: month, Dates: make([]systemRes.LogDateItem, 0)}\n\tif err = validateLogMonth(month); err != nil {\n\t\treturn result, err\n\t}\n\n\tlogRoot, exists, err := openConfiguredLogRoot()\n\tif err != nil {\n\t\treturn result, err\n\t}\n\tif !exists {","sourceCodeStart":13,"sourceCodeEnd":49,"githubUrl":"https://github.com/flipped-aurora/gin-vue-admin/blob/3136500ef380842b0eb6c4daa87c3f8a47fcf9e0/server/service/system/sys_log_viewer.go#L13-L49","documentation":"ErrInvalidLogPath indicates the requested log file path is not legal — the service rejects anything that escapes the configured log root or otherwise fails path-segment validation. validateLogAPIPath checks the path segments (e.g. rejecting traversal like \"../\"), and openValidatedLogFile also returns it when the date entry is a symlink or not a real directory. It is a security guard against path traversal and symlink attacks on the log viewer.","triggerScenarios":"ReadContent with apiPath containing \"..\", leading \"/\", backslashes, or unexpected segments; passing a date whose directory under the log root is a symlink or a regular file instead of a real directory; any non-whitelisted file path within a date directory.","commonSituations":"Probing/scanning clients attempting path traversal; old log layouts where date entries are files or symlinks; frontends concatenating raw user paths instead of whitelisted file names; renamed/moved log directories breaking assumptions.","solutions":["Request only files discovered via the ListFiles/ListDates APIs; never build paths from user input.","Remove \"..\", absolute prefixes, and backslashes from any constructed path; send a plain relative file name.","Check the log root on disk: date entries must be real directories, not symlinks; restructure or remove symlinked log dirs.","Keep log layout aligned with the expected <logRoot>/<YYYY-MM-DD>/<name>.log structure."],"exampleFix":"// before\nGET /logViewer/content?date=2025-08-01&path=../../etc/passwd  // ErrInvalidLogPath\n// after\nGET /logViewer/content?date=2025-08-01&path=gva-2025-08-01.log","handlingStrategy":"validation","validationCode":"func isSafeLogPath(p string) bool {\n\tif p == \"\" || strings.HasPrefix(p, \"/\") || strings.Contains(p, \"\\\\\") {\n\t\treturn false\n\t}\n\tfor _, seg := range strings.Split(p, \"/\") {\n\t\tif seg == \"\" || seg == \".\" || seg == \"..\" {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}","typeGuard":"func isKnownLogFile(path string, known []string) bool {\n\treturn slices.Contains(known, path)\n}","tryCatchPattern":"content, err := client.ReadContent(ctx, date, path)\nif err != nil && errors.Is(err, ErrInvalidLogPath) {\n\t// reject the input; do NOT retry with a modified path — refresh the file list instead\n}","preventionTips":["Only use file names returned by ListFiles; never assemble paths from user input.","Reject any path containing \"..\", leading \"/\", or backslashes before sending.","Keep log directories real directories — avoid symlinks under the log root.","Monitor rejected-path attempts as a security signal."],"tags":["go","security","path-traversal","log-viewer"],"backgroundTag":"path-traversal-blocked","analyzedSha":"3136500ef380842b0eb6c4daa87c3f8a47fcf9e0","analyzedAt":"2026-08-31T13:50:02.721Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}