{"record":{"id":"cb28f4935675a758","repo":"hashicorp/nomad","slug":"namespace-cannot-contain-template-delimiters-or-pa","errorCode":null,"errorMessage":"namespace cannot contain template delimiters or parenthesis","messagePattern":"namespace cannot contain template delimiters or parenthesis","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/allocrunner/taskrunner/secrets/nomad_provider.go","lineNumber":76,"sourceCode":"\t\t{{ range $k, $v := . }}\n\t\tsecret.%s.{{ $k }}={{ $v }}\n\t\t{{ end }}\n\t\t{{ end }}`,\n\t\tn.secret.Path, n.config.Namespace, n.secret.Name)\n\n\treturn &structs.Template{\n\t\tEmbeddedTmpl: data,\n\t\tDestPath:     filepath.Clean(filepath.Join(n.secretDir, n.tmplFile)),\n\t\tChangeMode:   structs.TemplateChangeModeNoop,\n\t\tOnce:         true,\n\t}\n}\n\n// validateNomadInputs ensures none of the user provided inputs contain delimiters\n// that could be used to inject other CT functions.\nfunc validateNomadInputs(conf *nomadProviderConfig, path string) error {\n\tif strings.ContainsAny(conf.Namespace, \"(){}\") {\n\t\treturn errors.New(\"namespace cannot contain template delimiters or parenthesis\")\n\t}\n\n\tif strings.ContainsAny(path, \"(){}\") {\n\t\treturn errors.New(\"path cannot contain template delimiters or parenthesis\")\n\t}\n\n\treturn nil\n}\n","sourceCodeStart":58,"sourceCodeEnd":85,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/client/allocrunner/taskrunner/secrets/nomad_provider.go#L58-L85","documentation":"The Nomad secrets template provider (nomad_provider.go) renders CT (Consul Template) snippets. validateNomadInputs rejects user-supplied namespaces that contain template delimiters '(' ')' '{' '}' so they cannot inject additional Consul Template functions or braces into the generated template. It returns 'namespace cannot contain template delimiters or parenthesis'.","triggerScenarios":"Creating a Nomad secrets provider via NewNomadProvider where conf.Namespace (from the secret stanza's config) contains any of the characters ( ) { } — e.g. namespace = \"prod(1)\" or a name with curly braces. The check is strings.ContainsAny(conf.Namespace, \"(){}\") and runs before the provider is constructed.","commonSituations":"Copy-pasting a namespace with stray whitespace/brackets, using templated or escaped namespace strings, or intentional-but-disallowed special characters in Vault/Nomad namespace names when wiring the secrets block into a task template.","solutions":["Remove the ( ) { } characters from the namespace value in the secrets config","URL-encode or otherwise escape the namespace at the source system (if the provider/API supports it) instead of embedding delimiters","Use a namespace alias/name that is plain alphanumeric plus - _ . / only","If the namespace legitimately needs these chars, upgrade Nomad or open an issue — validation is intentionally strict to block template injection"],"exampleFix":"// before\nsecret {\n  config = { namespace = \"prod(team-a)\" }\n}\n// after\nsecret {\n  config = { namespace = \"prod-team-a\" }\n}","handlingStrategy":"validation","validationCode":"// Go: pre-validate the namespace before constructing the provider\nfunc validNamespace(ns string) bool {\n\treturn ns != \"\" && !strings.ContainsAny(ns, \"(){}\")\n}\n// usage\nif !validNamespace(cfg.Namespace) {\n\treturn errors.New(\"namespace must not contain ( ) { }\")\n}","typeGuard":"func isDelimiterFree(s string) bool { return !strings.ContainsAny(s, \"(){}\") }","tryCatchPattern":"p, err := NewNomadProvider(ctx, secret, dir)\nif err != nil {\n\tif strings.Contains(err.Error(), \"namespace cannot contain\") {\n\t\treturn nil, fmt.Errorf(\"fix secrets config: namespace rejected: %w\", err)\n\t}\n\treturn nil, err\n}","preventionTips":["Restrict namespace names to [A-Za-z0-9._-/] at creation time in the source system","Lint Nomad job/secrets configs in CI for ( ) { } in namespace fields","Be careful with layered templating: interpolate values before they reach the secrets block"],"tags":["validation","template-injection","secrets","nomad"],"backgroundTag":"template-delimiter-injection","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"}