Skip to main content

SEC.AUTH.ROLE_DEPRECATED_PASSWORD_HASH — The account's password is stored under a retired verifier

  • Category: security
  • Severity: high
  • Level: 0
  • Confidence: deterministic
  • Downtime class: none — the finding is about an account, not about a statement
  • Stability: stable
  • Suites: audit
  • Applies to: PostgreSQL 18 · MySQL 8.4

One rule, two engines, two different problems

The reader maps PostgreSQL's md5 and MySQL's mysql_native_password onto the same value, because they are the same decision: the older of the two verifiers each engine offers. What they cost is not the same, so the finding says something different depending on where it fired.

On PostgreSQL, the md5 verifier is salted with the role name and nothing else. A digest captured anywhere is crackable offline, and — this is the part that surprises people — it is usable as the password itself against any server where a role of that name exists. Two databases that both have an app role share the exposure.

On MySQL, there is a second problem that has nothing to do with cryptography: mysql_native_password is disabled by default in 8.4 and removed in 9.0. The account stops being able to log in at the next major. Nothing in the connection string says so, and the usual moment to discover it is the upgrade window.

Bad

-- MySQL: the plugin 9.0 removes
ALTER USER 'app'@'%' IDENTIFIED WITH mysql_native_password BY 'secret';

Good

-- MySQL: current verifier, and one that still exists after the next major
ALTER USER 'app'@'%' IDENTIFIED WITH caching_sha2_password BY 'secret';

On PostgreSQL the order matters and is easy to get backwards: the verifier is written when the password is set, so changing password_encryption alone leaves every existing role exactly as it was. Set the parameter, then have each role set its password again.

How an account gets here at all

Not by being created today. On a stock MySQL 8.4 the plugin reports plugin_status = DISABLED, and CREATE USER … IDENTIFIED WITH mysql_native_password is refused outright with ERROR 1524. An account reaches this state by having been created on an older server and carried forward through an upgrade — which is exactly the case worth reporting, and exactly why a fresh installation shows nothing.

What is not reported

The engine's own accounts (mysql.sys, mysql.session, mysql.infoschema, and their PostgreSQL equivalents). They are marked as system accounts by the reader, and a finding a project cannot act on is noise whichever way it is right. Measured: on a stock 8.4 all three are caching_sha2_password anyway.

An account whose verifier could not be read is reported as undetermined, never as a current one. "Not deprecated" and "we could not see it" are the same sentence to a reader who cannot tell them apart, and only one of them is good news.