From 0be2770fd85fd6a8c675bafecdcae2ed326b82c2 Mon Sep 17 00:00:00 2001 From: herdiyana256 Date: Thu, 30 Jul 2026 12:38:28 +0700 Subject: [PATCH 1/2] mysql: don't enable cleartext passwords on unverified connections ConfigFromURL turned on AllowCleartextPasswords for every mysql:// URL while configuring no TLS, so anything that can answer on the database address can request an auth switch to mysql_clear_password and read the password off the wire. Enable it by default only when TLS is configured with certificate verification and no plaintext fallback; the allowCleartextPasswords parameter still forces it on for servers that need PAM/LDAP auth. --- mysql/mysql.go | 8 +++++++- mysql/mysql_test.go | 22 +++++++++++++++++++++- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/mysql/mysql.go b/mysql/mysql.go index 4cd1e2e4b1..0028f26ef3 100644 --- a/mysql/mysql.go +++ b/mysql/mysql.go @@ -79,7 +79,13 @@ func ConfigFromURL(u *url.URL) (cfg *mysql.Config, err error) { cfg.Passwd, _ = u.User.Password() cfg.DBName = dbName if _, ok := u.Query()["allowCleartextPasswords"]; !ok { - cfg.AllowCleartextPasswords = true + // The cleartext auth plugin hands the password to whatever answers on + // the database address, so it is only safe once the server's identity + // has been verified. Enable it by default only when the connection is + // TLS-protected with certificate verification and no plaintext + // fallback; otherwise applications must opt in explicitly with + // "allowCleartextPasswords=true". + cfg.AllowCleartextPasswords = cfg.TLS != nil && !cfg.TLS.InsecureSkipVerify && !cfg.AllowFallbackToPlaintext } cfg.AllowNativePasswords = true return cfg, nil diff --git a/mysql/mysql_test.go b/mysql/mysql_test.go index 71bb7f8427..952ca7a68d 100644 --- a/mysql/mysql_test.go +++ b/mysql/mysql_test.go @@ -99,10 +99,25 @@ func TestConfigFromURLCleartextPasswords(t *testing.T) { want bool }{ { - name: "default", + name: "default, no TLS", url: "mysql://user:password@localhost/db", + want: false, + }, + { + name: "default, TLS with verification", + url: "mysql://user:password@localhost/db?tls=true", want: true, }, + { + name: "default, TLS without verification", + url: "mysql://user:password@localhost/db?tls=skip-verify", + want: false, + }, + { + name: "default, TLS with plaintext fallback", + url: "mysql://user:password@localhost/db?tls=preferred", + want: false, + }, { name: "explicit false", url: "mysql://user:password@localhost/db?allowCleartextPasswords=false", @@ -113,6 +128,11 @@ func TestConfigFromURLCleartextPasswords(t *testing.T) { url: "mysql://user:password@localhost/db?allowCleartextPasswords=true", want: true, }, + { + name: "explicit true without TLS", + url: "mysql://user:password@localhost/db?allowCleartextPasswords=true&tls=false", + want: true, + }, } { t.Run(tc.name, func(t *testing.T) { u, err := url.Parse(tc.url) From 0dcfae6cde3acadfb8258eef66d2a05aef817ac7 Mon Sep 17 00:00:00 2001 From: herdiyana256 Date: Thu, 30 Jul 2026 16:43:36 +0700 Subject: [PATCH 2/2] mysql: cover the RawQuery-present-but-no-TLS-param branch in cleartext test ConfigFromURL takes a different code path (mysql.ParseDSN, which calls cfg.normalize() internally) when the URL has any query string at all, versus no query string. Add a case with an unrelated query param to exercise that branch explicitly, on top of the already-covered bare-URL case. --- mysql/mysql_test.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mysql/mysql_test.go b/mysql/mysql_test.go index 952ca7a68d..215d94b868 100644 --- a/mysql/mysql_test.go +++ b/mysql/mysql_test.go @@ -103,6 +103,11 @@ func TestConfigFromURLCleartextPasswords(t *testing.T) { url: "mysql://user:password@localhost/db", want: false, }, + { + name: "default, no TLS, other query params present", + url: "mysql://user:password@localhost/db?timeout=5s", + want: false, + }, { name: "default, TLS with verification", url: "mysql://user:password@localhost/db?tls=true",