Bug: Passwords containing \v (and other backslash escape sequences) are silently corrupted on config load in ProxySQL 3.x
Summary
ProxySQL 3.x upgraded its bundled libconfig from 1.7.3 to 1.8.1. libconfig 1.8.1 introduced
new escape-sequence rules for quoted strings (\v, \a, \b, and others). As a result, any
password stored in proxysql.cnf that contains a literal backslash followed by one of these
letters is silently corrupted at parse time: the two-character sequence is collapsed into a
single control character. The corrupted value is written to proxysql.db and used at runtime,
causing authentication failures that are difficult to diagnose because the password looks
correct in the original configuration file.
Affected versions
| Branch |
Version |
libconfig |
Affected |
| 2.x |
≤ 2.7.x |
1.7.3 |
No |
| 3.x |
≥ 3.0.5 |
1.8.1 |
Yes |
The libconfig upgrade was introduced in commit 88c34b30a (2025-10-02).
Versions 3.0.6, 3.0.7, and 3.0.8 are also affected.
Root cause
libconfig 1.8.1 added explicit escape-sequence rules in lib/scanner.l that did not exist in
1.7.3:
/* libconfig 1.8.1 — lib/scanner.l (new rules) */
<STRING>\\a { libconfig_scanctx_append_char(yyextra, '\a'); } /* 0x07 */
<STRING>\\b { libconfig_scanctx_append_char(yyextra, '\b'); } /* 0x08 */
<STRING>\\v { libconfig_scanctx_append_char(yyextra, '\v'); } /* 0x0B */
In libconfig 1.7.3 none of these rules existed. An unrecognised escape sequence fell through to
the catch-all rule:
/* libconfig 1.7.3 — catch-all: unrecognised escape → keep the backslash */
<STRING>\\. { libconfig_scanctx_append_char(yyextra, yytext[1]); }
So \v in a quoted string was preserved as the two-character literal \v in 1.7.3, but is
converted to the single byte 0x0B (vertical tab) in 1.8.1.
ProxySQL reads the corrupted value in Read_Global_Variables_from_configfile()
(lib/ProxySQL_Config.cpp) via group.lookupValue(n, value_string), which returns the
already-processed string from libconfig. The corrupted value is then stored in
global_variables and persisted to proxysql.db.
Steps to reproduce
Prerequisites
- ProxySQL ≥ 3.0.5 installed
- A password that contains a literal backslash followed by
v (e.g. a password manager or
secrets tool that generates such passwords)
Reproduction
-
Write a minimal proxysql.cnf with a monitor_password that contains \v:
datadir="/var/lib/proxysql"
mysql_variables:
{
monitor_username="proxymonitor"
monitor_password="pass\vword"
}
Note: \v here is two literal characters — ASCII 0x5C (backslash) followed by
ASCII 0x76 (v) — as produced by any config management tool writing a plaintext password
into the file.
-
Start ProxySQL forcing a fresh read from the config file:
proxysql --initial -f -c /etc/proxysql.cnf
-
Query the in-memory value via the admin interface:
SELECT variable_name,
variable_value,
HEX(variable_value)
FROM global_variables
WHERE variable_name = 'mysql-monitor_password';
Expected result
+-----------------------+----------------+------------------------------+
| variable_name | variable_value | HEX(variable_value) |
+-----------------------+----------------+------------------------------+
| mysql-monitor_password| pass\vword | 706173735C77 6F7264 |
+-----------------------+----------------+------------------------------+
0x5C (backslash) and 0x76 (v) are preserved as two separate bytes.
Actual result
+-----------------------+----------------+------------------------------+
| variable_name | variable_value | HEX(variable_value) |
+-----------------------+----------------+------------------------------+
| mysql-monitor_password| pass word | 70617373 0B 776F7264 |
+-----------------------+----------------+------------------------------+
\v has been collapsed to 0x0B (vertical tab). The value ProxySQL passes to
mysql_real_connect() no longer matches the password on the MySQL server.
Impact
- Monitor credentials: ProxySQL cannot authenticate to backend MySQL servers for health
checks (connect, ping, read_only, group-replication checks). All monitored servers are
marked as SHUNNED or unreachable.
- mysql_users passwords: Any user entry in
proxysql.cnf whose password field contains
\v is stored with the corrupted value. ProxySQL uses the corrupted bytes when verifying
client connections (via proxy_scramble_sha1), so clients with the correct password cannot
authenticate.
- Silent failure: The corruption happens at parse time inside libconfig. ProxySQL logs no
warning. The config file on disk still shows the original \v two-character sequence, making
the problem invisible until authentication failures are observed.
- Triggered by config reload: The issue is not limited to fresh starts. It also occurs when
LOAD MYSQL VARIABLES FROM CONFIG is executed (e.g. via a reload script triggered by
configuration management), even on a node that previously had a correct value in
proxysql.db.
Suggested fix
Option A — Escape backslashes on write (recommended)
When ProxySQL writes or re-serialises string values to proxysql.cnf, escape every backslash
by doubling it (\ → \\). libconfig then reads \\ as a single literal backslash,
preserving the original value regardless of what follows it:
monitor_password="pass\\vword" ← written to file
↓ libconfig 1.8.1 reads
pass\vword ← correct, two-character sequence restored
Option B — Escape on read
After calling group.lookupValue() in Read_Global_Variables_from_configfile(), re-escape
the string by reversing libconfig's known escape transformations (convert 0x0B back to \v,
0x07 back to \a, etc.). This is fragile because it cannot distinguish a genuine 0x0B
byte in a password from one that was produced by escape processing.
Option C — Pin libconfig to 1.7.3
Revert the libconfig dependency to 1.7.3 until a more robust fix is in place. This is a
regression relative to 2.7.x behaviour and eliminates the new escape rules entirely.
Workaround (operator-side)
Until a fix is released, operators can avoid the issue by ensuring that passwords written to
proxysql.cnf have their backslashes doubled before the file is rendered:
monitor_password="pass\\vword"
Config management tools (Puppet, Ansible, Chef, etc.) should apply this escaping when
templating proxysql.cnf.
Environment used for analysis
- ProxySQL 3.0.5
- libconfig 1.8.1 (bundled at
deps/libconfig/libconfig-1.8.1.tar.gz)
- MySQL 8.4.7 backend
- RHEL / CentOS 8, x86_64
Bug: Passwords containing
\v(and other backslash escape sequences) are silently corrupted on config load in ProxySQL 3.xSummary
ProxySQL 3.x upgraded its bundled libconfig from 1.7.3 to 1.8.1. libconfig 1.8.1 introduced
new escape-sequence rules for quoted strings (
\v,\a,\b, and others). As a result, anypassword stored in
proxysql.cnfthat contains a literal backslash followed by one of theseletters is silently corrupted at parse time: the two-character sequence is collapsed into a
single control character. The corrupted value is written to
proxysql.dband used at runtime,causing authentication failures that are difficult to diagnose because the password looks
correct in the original configuration file.
Affected versions
The libconfig upgrade was introduced in commit
88c34b30a(2025-10-02).Versions 3.0.6, 3.0.7, and 3.0.8 are also affected.
Root cause
libconfig 1.8.1 added explicit escape-sequence rules in
lib/scanner.lthat did not exist in1.7.3:
In libconfig 1.7.3 none of these rules existed. An unrecognised escape sequence fell through to
the catch-all rule:
So
\vin a quoted string was preserved as the two-character literal\vin 1.7.3, but isconverted to the single byte
0x0B(vertical tab) in 1.8.1.ProxySQL reads the corrupted value in
Read_Global_Variables_from_configfile()(
lib/ProxySQL_Config.cpp) viagroup.lookupValue(n, value_string), which returns thealready-processed string from libconfig. The corrupted value is then stored in
global_variablesand persisted toproxysql.db.Steps to reproduce
Prerequisites
v(e.g. a password manager orsecrets tool that generates such passwords)
Reproduction
Write a minimal
proxysql.cnfwith amonitor_passwordthat contains\v:Start ProxySQL forcing a fresh read from the config file:
Query the in-memory value via the admin interface:
Expected result
0x5C(backslash) and0x76(v) are preserved as two separate bytes.Actual result
\vhas been collapsed to0x0B(vertical tab). The value ProxySQL passes tomysql_real_connect()no longer matches the password on the MySQL server.Impact
checks (
connect,ping,read_only, group-replication checks). All monitored servers aremarked as
SHUNNEDor unreachable.proxysql.cnfwhosepasswordfield contains\vis stored with the corrupted value. ProxySQL uses the corrupted bytes when verifyingclient connections (via
proxy_scramble_sha1), so clients with the correct password cannotauthenticate.
warning. The config file on disk still shows the original
\vtwo-character sequence, makingthe problem invisible until authentication failures are observed.
LOAD MYSQL VARIABLES FROM CONFIGis executed (e.g. via a reload script triggered byconfiguration management), even on a node that previously had a correct value in
proxysql.db.Suggested fix
Option A — Escape backslashes on write (recommended)
When ProxySQL writes or re-serialises string values to
proxysql.cnf, escape every backslashby doubling it (
\→\\). libconfig then reads\\as a single literal backslash,preserving the original value regardless of what follows it:
Option B — Escape on read
After calling
group.lookupValue()inRead_Global_Variables_from_configfile(), re-escapethe string by reversing libconfig's known escape transformations (convert
0x0Bback to\v,0x07back to\a, etc.). This is fragile because it cannot distinguish a genuine0x0Bbyte in a password from one that was produced by escape processing.
Option C — Pin libconfig to 1.7.3
Revert the libconfig dependency to 1.7.3 until a more robust fix is in place. This is a
regression relative to 2.7.x behaviour and eliminates the new escape rules entirely.
Workaround (operator-side)
Until a fix is released, operators can avoid the issue by ensuring that passwords written to
proxysql.cnfhave their backslashes doubled before the file is rendered:Config management tools (Puppet, Ansible, Chef, etc.) should apply this escaping when
templating
proxysql.cnf.Environment used for analysis
deps/libconfig/libconfig-1.8.1.tar.gz)