{"record":{"id":"6d46d0a345661995","repo":"hashicorp/nomad","slug":"reading-secret-file-prohibited-s","errorCode":null,"errorMessage":"Reading secret file prohibited: %s","messagePattern":"Reading secret file prohibited: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/allocdir/alloc_dir.go","lineNumber":437,"sourceCode":"\t}\n\n\trequestedPath, err := filepath.Abs(filepath.Join(resolvedAllocDir, path))\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to resolve requested path: %w\", err)\n\t}\n\n\tif err := escapingfs.ChildEscapesParentDir(resolvedAllocDir, requestedPath); err != nil {\n\t\treturn \"\", fmt.Errorf(\"path escapes the alloc directory\")\n\t}\n\n\ta.mu.RLock()\n\tdefer a.mu.RUnlock()\n\n\t// Check it does not access the secrets or private directories\n\tfor _, taskDir := range a.TaskDirs {\n\t\trps := strings.ReplaceAll(requestedPath, \"/Secrets\", \"/secrets\")\n\t\tif err := escapingfs.ChildEscapesParentDir(taskDir.SecretsDir, rps); err == nil {\n\t\t\treturn \"\", fmt.Errorf(\"Reading secret file prohibited: %s\", path)\n\t\t}\n\n\t\trpp := strings.ReplaceAll(requestedPath, \"/Private\", \"/private\")\n\t\tif err := escapingfs.ChildEscapesParentDir(taskDir.PrivateDir, rpp); err == nil {\n\t\t\treturn \"\", fmt.Errorf(\"Reading secret file prohibited: %s\", path)\n\t\t}\n\t}\n\n\treturn requestedPath, nil\n}\n\n// Stat returns information about the file at a path relative to the alloc dir\nfunc (a *AllocDir) Stat(path string) (*cstructs.AllocFileInfo, error) {\n\n\tsanitizedPath, err := a.sanitizePath(path)\n\tif err != nil {\n\t\treturn nil, err\n\t}","sourceCodeStart":419,"sourceCodeEnd":455,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/client/allocdir/alloc_dir.go#L419-L455","documentation":"sanitizePath() additionally blocks access to any task's SecretsDir. If the requested path resolves inside a SecretsDir, this error is returned (checked case-insensitively by replacing /Secrets with /secrets). This protects Task Role Credentials/vault secrets from the file API.","triggerScenarios":"Calling List/Stat/ReadAt/BlockUntilExists/ChangeEvents with a path resolving inside a task's secrets directory (e.g. secrets/token or .../Secrets/...).","commonSituations":"Templates or tooling trying to read the vault-derived secret token file; filesystem snapshot/debug tooling enumerating all task files including secrets; user asking the API for secrets dir contents.","solutions":["Do not access the secrets dir via the alloc filesystem API; use the secret's intended delivery mechanism (template, env, vault integration)","Move application config that must be readable out of the secrets dir into a normal task dir path","If legitimate access is needed, read the file inside the task process itself rather than via AllocDir APIs"],"exampleFix":"// before\nallocDir.ReadAt(\"task/web/secrets/token\", 0)\n// after\n// read inside the task, e.g. via exec or template delivery, not the file API","handlingStrategy":"validation","validationCode":"if strings.Contains(strings.ToLower(relPath), \"secrets\") {\n    return fmt.Errorf(\"refusing to access secrets dir\")\n}","typeGuard":null,"tryCatchPattern":"data, err := allocDir.ReadAt(relPath, 0)\nif err != nil && strings.Contains(err.Error(), \"Reading secret file prohibited\") {\n    return ErrSecretsAccessDenied // request is not permitted by design\n}","preventionTips":["Never read secrets via the alloc file API; use templates/env/vault delivery","Exclude secrets dir from debug snapshots and file walkers","Educate tooling that the secrets dir is intentionally unreadable"],"tags":["security","secrets","path-traversal"],"backgroundTag":"secrets-dir-access-denied","analyzedSha":"482b49bf1aec006f089bcfc7e632d8f6ac303e5e","analyzedAt":"2026-09-04T07:54:14.808Z","contentChangedAt":"2026-09-04T07:54:14.808Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}