From 6963432600c3c6b5ee816f58151849f627f28889 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Fri, 24 Jul 2026 10:50:58 -0700 Subject: [PATCH] Send the 802.1X password over stdin instead of argv argv is world-readable in /proc for every local process while the connection attempt runs. Create the profile without the secret, then set it through nmcli's scriptable connection editor, which reads from stdin. Co-Authored-By: Claude Fable 5 --- shell/plugins/panels/network/Model.js | 9 +++++++-- shell/plugins/panels/network/Panel.qml | 16 +++++++++++++++- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/shell/plugins/panels/network/Model.js b/shell/plugins/panels/network/Model.js index 8f92b760..c16b24ed 100644 --- a/shell/plugins/panels/network/Model.js +++ b/shell/plugins/panels/network/Model.js @@ -232,11 +232,16 @@ function isProtected(security, openSecurity) { return security !== openSecurity } +// The password arrives on stdin and reaches nmcli through the scriptable +// `connection edit` editor -- argv is world-readable in /proc, so the secret +// must never be an argument (printf is a bash builtin, so no process spawns +// with it either). var enterpriseConnectScript = - "u=$(uuidgen);" + + "u=$(uuidgen); IFS= read -r pw;" + " nmcli connection add type wifi con-name \"$1\" ssid \"$1\" connection.uuid \"$u\"" + " wifi-sec.key-mgmt wpa-eap 802-1x.eap peap 802-1x.phase2-auth mschapv2" + - " 802-1x.identity \"$2\" 802-1x.password \"$3\" 802-1x.auth-timeout 8" + + " 802-1x.identity \"$2\" 802-1x.auth-timeout 8 >/dev/null" + + " && printf 'set 802-1x.password %s\\nsave\\nquit\\n' \"$pw\" | nmcli connection edit uuid \"$u\" >/dev/null" + " && nmcli connection up uuid \"$u\"" + " || { nmcli connection delete uuid \"$u\" >/dev/null 2>&1; false; }" diff --git a/shell/plugins/panels/network/Panel.qml b/shell/plugins/panels/network/Panel.qml index 0e3830b9..031602aa 100644 --- a/shell/plugins/panels/network/Panel.qml +++ b/shell/plugins/panels/network/Panel.qml @@ -579,10 +579,24 @@ Panel { function connectEnterprise(ssid, identity, passphrase) { runNetworkAction("connect", networkForSsid(ssid), function(network) { - Quickshell.execDetached(["bash", "-c", Model.enterpriseConnectScript, "nmcli-eap", ssid, identity, passphrase]) + enterpriseConnect.secret = passphrase + enterpriseConnect.command = ["bash", "-c", Model.enterpriseConnectScript, "nmcli-eap", ssid, identity] + enterpriseConnect.running = true }) } + // Creates and activates the 802.1X profile (see Model.enterpriseConnectScript). + // The password goes over stdin, never argv. + Process { + id: enterpriseConnect + property string secret: "" + stdinEnabled: true + onStarted: { + write(secret + "\n") + secret = "" + } + } + function disconnect(network) { runNetworkAction("disconnect", network || connectedWifiNetwork, function(net) { net.disconnect() }) }