[client] Require privilege to relax TLS on a resolved upload destination

requirePrivilegeForUploadURL returned early on an empty URL, which was correct
while an empty URL meant "do not upload": there was no destination for
--upload-bundle-insecure to weaken. Now an empty URL means "use the destination
the management server published", so an unprivileged local caller could send
upload=true with an empty URL and uploadInsecure=true and have the root daemon
PUT the bundle to that destination with TLS verification disabled.

Gate the insecure flag on the empty-URL path too. A named URL keeps its existing
order, so a malformed one still reports InvalidArgument rather than a privilege
error.
This commit is contained in:
riccardom
2026-09-10 16:38:41 +02:00
parent 9f6d17b9e8
commit fcb9b02451
2 changed files with 12 additions and 0 deletions
+9
View File
@@ -53,6 +53,15 @@ func uiLogOpener(id ipcauth.Identity, identified bool) debug.LogOpener {
// refused for an unprivileged caller regardless of the host.
func requirePrivilegeForUploadURL(ctx context.Context, rawURL string, insecure bool) error {
if rawURL == "" {
// An empty URL is not "no upload": the daemon then resolves the
// destination the management server published. Relaxing TLS on the way
// there exposes the bundle exactly as naming the host outright would, so
// it needs the same privilege.
if insecure {
return denyPrivileged(ctx,
"uploading a debug bundle without transport security (--upload-bundle-insecure)",
ipcauth.ElevatedCommand("netbird debug bundle -U --upload-bundle-insecure"))
}
return nil
}
+3
View File
@@ -116,6 +116,9 @@ func TestRequirePrivilegeForUploadURL(t *testing.T) {
rootAlso bool
}{
{name: "no upload", url: "", unprivOK: true},
// An empty URL resolves to the destination management published, so
// relaxing TLS towards it needs the same privilege as naming a host.
{name: "insecure with no URL", url: "", insecure: true, rootAlso: true},
{name: "default service", url: types.DefaultBundleURL, unprivOK: true},
{name: "default service, other path", url: "https://upload.debug.netbird.io/other", unprivOK: true},
{name: "loopback exfiltration endpoint", url: "https://127.0.0.1:8080/upload-url", rootAlso: true},