From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from gate001.proxmox.com (gate001.proxmox.com [IPv6:2a0f:8001:1:32::40]) by lore.proxmox.com (Postfix) with ESMTPS id 41ED51FF09D for ; Sun, 01 Nov 2026 22:40:24 +0100 (CET) Received: from gate001.proxmox.com (localhost.localdomain [127.0.0.1]) by gate001.proxmox.com (Proxmox) with ESMTP id E8717217ED; Sun, 01 Nov 2026 22:38:55 +0100 (CET) From: Thomas Lamprecht To: pve-devel@lists.proxmox.com Subject: [PATCH manager 09/10] report: redact credentials in URLs, options and environment variables Date: Sun, 1 Nov 2026 22:34:58 +0100 Message-ID: <20261101213835.353604-10-t.lamprecht@proxmox.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20261101213835.353604-1-t.lamprecht@proxmox.com> References: <20261101213835.353604-1-t.lamprecht@proxmox.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Bm-Milter-Handled: 55990f41-d878-4baa-be0a-ee34c49e34d2 X-Bm-Transport-Timestamp: 1793569121332 X-SPAM-LEVEL: Spam detection results: 0 AWL 0.407 Adjusted score from AWL reputation of From: address DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment (newer systems) RCVD_IN_DNSWL_MED -2.3 Sender listed at https://www.dnswl.org/, medium trust SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record WEIRD_PORT 0.001 Uses non-standard port number for HTTP Message-ID-Hash: K25ADKSHUUZUXY23GDPS4QJ2LTQNXHKC X-Message-ID-Hash: K25ADKSHUUZUXY23GDPS4QJ2LTQNXHKC X-MailFrom: t.lamprecht@proxmox.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.10 Precedence: list List-Id: Proxmox VE development discussion List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: Some credentials in the report are not covered by any schema: the password in a URL, as used in APT sources or the HTTP proxy setting of datacenter.cfg, mount options like password= in fstab, and container environment variables like DB_PASSWORD, which the env property stores as raw lxc keys. Replace passwords in URLs and values whose name suggests a credential, in the whole report. This is a heuristic. It also catches such options on command lines as shown by top, but not values passed as separate arguments, nor the part of a value after a space or comma, except for environment variables. Signed-off-by: Thomas Lamprecht --- PVE/Report.pm | 22 ++++++++++++- test/Makefile | 6 +++- test/report_test.pl | 78 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 104 insertions(+), 2 deletions(-) create mode 100755 test/report_test.pl diff --git a/PVE/Report.pm b/PVE/Report.pm index 7182c091d..fa7fc4280 100644 --- a/PVE/Report.pm +++ b/PVE/Report.pm @@ -67,6 +67,26 @@ my sub redact_section_config { return $class->redact_raw_config($raw, $redaction_placeholder); } +# names like password, db_pass, ADMIN_TOKEN, SECRET_KEY or api_key +my $credential_name_re = qr/ + (? /dev/null 2>&1") == 0 } @@ -276,7 +296,7 @@ sub generate { } } - return $report; + return redact_credentials($report); } 1; diff --git a/test/Makefile b/test/Makefile index 2dfd20a41..91761579d 100644 --- a/test/Makefile +++ b/test/Makefile @@ -5,7 +5,7 @@ all: export PERLLIB=.. .PHONY: check -check: test-replication test-balloon test-vzdump test-osd test-ceph-health test-ceph-services test-ceph-auth test-ceph-key-migration test-ceph-lockbox-migration test-custom-cpu-models test-pvesh +check: test-replication test-balloon test-vzdump test-osd test-ceph-health test-ceph-services test-ceph-auth test-ceph-key-migration test-ceph-lockbox-migration test-custom-cpu-models test-pvesh test-report .PHONY: test-balloon test-balloon: @@ -61,6 +61,10 @@ test-custom-cpu-models: test-pvesh: ./pvesh_test.pl +.PHONY: test-report +test-report: + ./report_test.pl + .PHONY: install install: diff --git a/test/report_test.pl b/test/report_test.pl new file mode 100755 index 000000000..444e4344f --- /dev/null +++ b/test/report_test.pl @@ -0,0 +1,78 @@ +#!/usr/bin/perl + +use v5.36; + +use lib ('.', '..'); + +use Test::More; + +use PVE::Report; + +my $tests = [ + [ + 'APT source with credentials', + 'deb https://user:s3cr:et@deb.example.com/debian trixie main', + 'deb https://user:@deb.example.com/debian trixie main', + ], + [ + 'URL with an unencoded @ in the password', + 'http_proxy: http://user:p@ss@proxy.example.com:3128/', + 'http_proxy: http://user:@proxy.example.com:3128/', + ], + [ + 'URL with an @ in the user name', + 'http_proxy: http://user@corp.example:s3cret@proxy.example.com:3128/', + 'http_proxy: http://user@corp.example:@proxy.example.com:3128/', + ], + [ + 'proxy URL with port and without credentials', + 'http_proxy: http://proxy.example.com:3128/', + 'http_proxy: http://proxy.example.com:3128/', + ], + [ + 'URL with user only', + 'URIs: https://user@deb.example.com/debian', + 'URIs: https://user@deb.example.com/debian', + ], + [ + 'URL with user and port only', + 'ssh://root@host.example:22/srv', + 'ssh://root@host.example:22/srv', + ], + [ + 'CIFS mount options', + '//srv/share /mnt cifs username=foo,password=bar,uid=0 0 0', + '//srv/share /mnt cifs username=foo,password=,uid=0 0 0', + ], + [ + 'CIFS password with an escaped comma', + 'username=foo,password=a,,b,password2=new,uid=0', + 'username=foo,password=,password2=,uid=0', + ], + [ + 'Ceph mount options', + 'mon1:/ /mnt ceph name=admin,secret=AQB+abc==,secretfile=/etc/ceph/s 0 0', + 'mon1:/ /mnt ceph name=admin,secret=,secretfile=/etc/ceph/s 0 0', + ], + [ + 'command line options', + 'tool --pass=hunter2 --bypass=1 --db-password=x --api_key=y passthrough=on', + 'tool --pass= --bypass=1 --db-password= --api_key= passthrough=on', + ], + [ + 'container environment', + "lxc.environment.runtime: ADMIN_TOKEN=\$argon2id\$v=19\$m=65540,t=3,p=4\$c2FsdA\$aGFzaA\n" + . "lxc.environment.runtime: DB_PASSWORD=correct horse\n" + . "lxc.environment.runtime: TZ=Europe/Vienna\n", + "lxc.environment.runtime: ADMIN_TOKEN=\n" + . "lxc.environment.runtime: DB_PASSWORD=\n" + . "lxc.environment.runtime: TZ=Europe/Vienna\n", + ], +]; + +for my $test ($tests->@*) { + my ($name, $in, $out) = $test->@*; + is(PVE::Report::redact_credentials($in), $out, $name); +} + +done_testing(); -- 2.47.3