puppetlabs/puppet · error · ArgumentError
invalid key
Error message
invalid key
What it means
The YAML terminus's path() rejects indirection keys matching Puppet::Indirector::BadNameRegexp (patterns like a leading '../', '/..' inside the name, or a leading '/'), logs a critical message about directory traversal, and raises ArgumentError 'invalid key'. The check prevents keys from escaping the terminus's base directory, so it fires on absolute paths and dot-dot relative paths used as indirection keys — whether from a bug or a deliberate traversal attempt.
Source
Thrown at lib/puppet/indirector/yaml.rb:42
file = path(request.key)
basedir = File.dirname(file)
# This is quite likely a bad idea, since we're not managing ownership or modes.
Dir.mkdir(basedir) unless Puppet::FileSystem.exist?(basedir)
begin
Puppet::Util::Yaml.dump(request.instance, file)
rescue TypeError => detail
Puppet.err _("Could not save %{indirection} %{request}: %{detail}") % { indirection: name, request: request.key, detail: detail }
end
end
# Return the path to a given node's file.
def path(name, ext = '.yaml')
if name =~ Puppet::Indirector::BadNameRegexp then
Puppet.crit(_("directory traversal detected in %{indirection}: %{name}") % { indirection: self.class, name: name.inspect })
raise ArgumentError, _("invalid key")
end
base = Puppet.run_mode.server? ? Puppet[:yamldir] : Puppet[:clientyamldir]
File.join(base, self.class.indirection_name.to_s, name.to_s + ext)
end
def destroy(request)
file_path = path(request.key)
Puppet::FileSystem.unlink(file_path) if Puppet::FileSystem.exist?(file_path)
end
def search(request)
Dir.glob(path(request.key, '')).collect do |file|
load_file(file)
end
end
protectedView on GitHub (pinned to e227c27540)
Solutions
- Sanitize keys before use: name = File.basename(key) (and reject empty results)
- Validate certnames/identifiers at ingress: reject '/' and '..' in names that will become indirection keys
- Find the caller passing the raw path — the crit log line names the indirection and the offending name.inspect
- If traversal appeared in server logs from external traffic, treat as a probing attempt and check access controls (auth.conf) on the affected endpoints
Example fix
# before key = params[:node] # attacker-controlled: '../../etc/passwd' Puppet::Node.indirection.find(key) # crit + ArgumentError: invalid key # after key = File.basename(params[:node].to_s) raise ArgumentError, 'bad node name' if key.empty? || key =~ /\A\.+\z/ Puppet::Node.indirection.find(key)
Defensive patterns
Strategy: validation
Validate before calling
def safe_indirection_key?(name)
name.is_a?(String) && !name.empty? && name !~ Puppet::Indirector::BadNameRegexp && !name.start_with?('/')
end
raise ArgumentError, 'invalid key' unless safe_indirection_key?(user_input) Type guard
def safe_indirection_key?(name) name.is_a?(String) && !name.empty? && name !~ Puppet::Indirector::BadNameRegexp end
Prevention
- Apply File.basename plus a charset whitelist to every externally supplied name used as a key
- Reject certnames containing '/' or '..' at issuance time
- Treat any occurrence of this error in server logs as a security signal and audit the source
When it happens
Trigger: Calling a yaml/msgpack/json-backed indirection with key '../../../etc/passwd', '/etc/shadow', or 'cert/../other'; commonly triggered when certnames or filenames containing slashes/dotdot segments are passed straight through as request keys (e.g., a node whose certname was issued with a '/' in it).
Common situations: Security testing / fuzzing of Puppet REST endpoints; bugs where File.basename is forgotten and full paths are passed as keys; compromised or malformed ENC output feeding crafted node names into yaml store paths.
Related errors
- invalid key
- invalid key
- Instance name %{name} does not match requested key %{key}
- Invalid instance type %{klass}, expected %{model_type}
- Attempt to install file with an invalid path into %{path} un
AI-assisted analysis of puppetlabs/puppet@e227c27540 (2026-08-21).
Data as JSON: /api/errors/bd4594dab9c8fe6e.
Report an issue: GitHub.