From d802f84da3746f201187b8ffa558a4c061cb7ee6 Mon Sep 17 00:00:00 2001 From: Ihar Kryvanos Date: Thu, 20 Aug 2026 15:05:08 +0200 Subject: [PATCH] ansible: pin ANSIBLE_CONFIG to disable ambient config discovery ansible-playbook auto-discovers a configuration file from the current working directory (./ansible.cfg) or the home directory (~/.ansible.cfg). Because the server runs privileged and its working directory is not guaranteed to be trusted, a caller able to drop a file in those locations could supply a config that points plugin/library/roles paths at attacker-controlled code and gain execution on the next run. Pin ANSIBLE_CONFIG via a new bindable AnsibleConfigFile variable defaulting to os.DevNull, which loads an empty config and disables that discovery. Operators can set it to a trusted path to supply a real configuration. --- services/ansible/server/ansible.go | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/services/ansible/server/ansible.go b/services/ansible/server/ansible.go index 752cae25..2b2b06c6 100644 --- a/services/ansible/server/ansible.go +++ b/services/ansible/server/ansible.go @@ -38,6 +38,18 @@ var ( // AnsiblePlaybookBin is the location to the ansible binary. Binding this to a flag is often useful. AnsiblePlaybookBin = "/usr/bin/ansible-playbook" + // AnsibleConfigFile pins the configuration file used by ansible-playbook via + // the ANSIBLE_CONFIG environment variable. Pinning it is important because + // ansible otherwise auto-discovers a config file from the process working + // directory (./ansible.cfg) or the home directory (~/.ansible.cfg). Since the + // server runs privileged and its working directory is not guaranteed to be + // trusted, a caller able to drop a file in those locations could supply a + // config that points plugin/library/roles paths at attacker-controlled code + // and gain execution on the next run. Defaulting to os.DevNull loads an empty + // config and disables that discovery; set it to a trusted path to supply a + // real configuration. Binding this to a flag is often useful. + AnsibleConfigFile = os.DevNull + // A test hook so we can take the args passed and transform them as needed. cmdArgsTransform = func(input []string) []string { return input @@ -118,7 +130,11 @@ func (s *server) Run(ctx context.Context, req *pb.RunRequest) (*pb.RunReply, err cmdArgs = cmdArgsTransform(cmdArgs) - run, err := util.RunCommand(ctx, AnsiblePlaybookBin, cmdArgs) + // Pin ANSIBLE_CONFIG so ansible does not auto-load ./ansible.cfg from the + // (untrusted) working directory or ~/.ansible.cfg from the home directory. + run, err := util.RunCommand(ctx, AnsiblePlaybookBin, cmdArgs, + util.EnvVar("ANSIBLE_CONFIG="+AnsibleConfigFile), + ) if err != nil { recorder.CounterOrLog(ctx, ansibleRunFailureCounter, 1, attribute.String("reason", "run_err")) return nil, err