Skip to content

Avoid shell interpretation of HAB_LISTEN_CTL in secrets bootstrap#4205

Open
tas50 wants to merge 1 commit into
chef:mainfrom
tas50:fix-csc-secrets-bootstrap-command-injection
Open

Avoid shell interpretation of HAB_LISTEN_CTL in secrets bootstrap#4205
tas50 wants to merge 1 commit into
chef:mainfrom
tas50:fix-csc-secrets-bootstrap-command-injection

Conversation

@tas50

@tas50 tas50 commented Jun 6, 2026

Copy link
Copy Markdown
Contributor

Problem

The secrets bootstrap loop in src/chef-server-ctl/habitat/config/secrets-bootstrap.rb builds a hab config apply command as a single string and executes it with system cmd, appending the value of the HAB_LISTEN_CTL environment variable unescaped:

cmd = "hab config apply chef-server-ctl.default #{version} {{pkg.svc_data_path}}/hab-secrets-modified.toml"
sup_listen_ctl = ENV["HAB_LISTEN_CTL"]
cmd += " --remote-sup #{sup_listen_ctl}" if sup_listen_ctl
system cmd

Passing a single string to system runs it through a shell. Any shell metacharacters in HAB_LISTEN_CTL are therefore interpreted by the shell instead of being passed to hab as a literal argument, allowing command injection via that environment variable.

Fix

Build an explicit argument vector and call system(*cmd). With multiple arguments Ruby does not invoke a shell, so HAB_LISTEN_CTL is delivered to hab as a single literal argument:

cmd = ["hab", "config", "apply", "chef-server-ctl.default", version.to_s,
       "{{pkg.svc_data_path}}/hab-secrets-modified.toml"]
sup_listen_ctl = ENV["HAB_LISTEN_CTL"]
cmd += ["--remote-sup", sup_listen_ctl] if sup_listen_ctl
system(*cmd)

The Habitat template placeholder ({{pkg.svc_data_path}}) is unchanged and is still rendered before the script runs, exactly as it is for the adjacent File.write call.

Note: this file is a Habitat config template; I verified the Ruby with ruby -c.

The secrets bootstrap loop built a 'hab config apply' command as a
single string and ran it with `system cmd`, appending the value of the
HAB_LISTEN_CTL environment variable unescaped:

    cmd += " --remote-sup #{sup_listen_ctl}" if sup_listen_ctl
    system cmd

Passing a single string to system runs it through a shell, so any shell
metacharacters in HAB_LISTEN_CTL would be interpreted rather than passed
to hab as a literal argument.

Build an explicit argument vector and call system(*cmd) so no shell is
involved and the environment variable is treated as a single literal
argument. The Habitat template placeholder is unchanged and continues
to be rendered before the script runs.

Signed-off-by: Tim Smith <tsmith84@proton.me>
@tas50 tas50 requested review from a team as code owners June 6, 2026 16:23
@netlify

netlify Bot commented Jun 6, 2026

Copy link
Copy Markdown

👷 Deploy Preview for chef-server processing.

Name Link
🔨 Latest commit 1bf8ef6
🔍 Latest deploy log https://app.netlify.com/projects/chef-server/deploys/6a244972eecf890008cbb183

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant