{"record":{"id":"17023bbfde0dcf26","repo":"iflytek/astron-agent","slug":"credential-file-must-be-a-regular-non-symbolic-link-file-17023b","errorCode":null,"errorMessage":"credential file must be a regular non-symbolic-link file","messagePattern":"credential file must be a regular non-symbolic-link file","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/tenant/config/credential_file_unix.go","lineNumber":24,"sourceCode":"\t\"errors\"\n\t\"os\"\n\n\t\"golang.org/x/sys/unix\"\n)\n\n// openCredentialFileNoFollow resolves and opens the credential in one kernel\n// operation. O_NOFOLLOW prevents a path swap to a symbolic link between a\n// separate path inspection and open; O_NONBLOCK prevents a hostile FIFO from\n// blocking startup before the descriptor type is checked with fstat.\nfunc openCredentialFileNoFollow(fileName string) (*os.File, error) {\n\tfd, err := unix.Open(\n\t\tfileName,\n\t\tunix.O_RDONLY|unix.O_CLOEXEC|unix.O_NOFOLLOW|unix.O_NONBLOCK,\n\t\t0,\n\t)\n\tif err != nil {\n\t\tif errors.Is(err, unix.ELOOP) {\n\t\t\treturn nil, errors.New(\n\t\t\t\t\"credential file must be a regular non-symbolic-link file\",\n\t\t\t)\n\t\t}\n\t\treturn nil, errors.New(\"credential file is unavailable\")\n\t}\n\treturn os.NewFile(uintptr(fd), fileName), nil\n}\n","sourceCodeStart":6,"sourceCodeEnd":32,"githubUrl":"https://github.com/iflytek/astron-agent/blob/5e758547a83371a5a4b29dadf4ac03e8dd527635/core/tenant/config/credential_file_unix.go#L6-L32","documentation":"The unix build of openCredentialFileNoFollow opens the credential file with O_NOFOLLOW; when the kernel returns ELOOP the path is a symbolic link and the function rejects it. Like the portable variant, this prevents symlink attacks on credential paths. A real regular file must be present at the path.","triggerScenarios":"Calling openCredentialFileNoFollow on Linux/Unix with fileName being a symlink (unix.Open returns ELOOP due to O_NOFOLLOW).","commonSituations":"Kubernetes-mounted secrets are symlinked files inside ..data directories — passing the symlinked leaf path directly triggers this; provisioning scripts creating symlinks to secrets; Docker secrets mounted via symlinks (e.g. /run/secrets/... indirection).","solutions":["Pass the fully resolved real path to the regular file (resolve the symlink outside the library, e.g. filepath.EvalSymlinks before calling, then verify the result is regular)","Configure the credential path to the final regular file rather than a symlinked indirection (e.g. mount secrets with subPath in Kubernetes)","Replace the symlink with a real copy of the secret file"],"exampleFix":"// before\ncfg.CredentialFile = \"/run/secrets/tenant.key\"        // symlink created by secret store\n// after\nreal, err := filepath.EvalSymlinks(\"/run/secrets/tenant.key\")\ncfg.CredentialFile = real                              // resolved regular file","handlingStrategy":"validation","validationCode":"real, err := filepath.EvalSymlinks(path)\nif err != nil {\n    return err\n}\ninfo, err := os.Lstat(real)\nif err != nil || !info.Mode().IsRegular() {\n    return fmt.Errorf(\"credential path %q must resolve to a regular file\", path)\n}","typeGuard":"func isRealRegularFile(path string) bool {\n    real, err := filepath.EvalSymlinks(path)\n    if err != nil {\n        return false\n    }\n    info, err := os.Lstat(real)\n    return err == nil && info.Mode().IsRegular()\n}","tryCatchPattern":"f, err := openCredentialFileNoFollow(path)\nif err != nil {\n    if err.Error() == \"credential file must be a regular non-symbolic-link file\" {\n        resolved, rerr := filepath.EvalSymlinks(path)\n        if rerr == nil {\n            f, err = openCredentialFileNoFollow(resolved)\n        }\n    }\n    if err != nil {\n        return err\n    }\n}","preventionTips":["Configure the fully resolved secret path, not a symlinked indirection","In Kubernetes, use subPath secret mounts so files are regular","Check /run/secrets-style paths: many secret stores mount symlinks — resolve first","Document the no-symlink requirement wherever credential paths are configured"],"tags":["go","unix","symlink","security"],"backgroundTag":"invalid-config-value","analyzedSha":"5e758547a83371a5a4b29dadf4ac03e8dd527635","analyzedAt":"2026-09-12T08:03:51.356Z","contentChangedAt":"2026-09-12T08:03:51.356Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}