Skip to content

Passwords containing \v (and other backslash escape sequences) are silently corrupted on config load in ProxySQL 3.x #5766

@vwerner74

Description

@vwerner74

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

  1. 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.

  2. Start ProxySQL forcing a fresh read from the config file:

    proxysql --initial -f -c /etc/proxysql.cnf
  3. 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions