Skip to main content

SEC.AUTH.ROLE_NO_PASSWORD — The account can log in and has no password at all

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

Why this one is critical when the other account findings are not

Every other account rule in this package describes something an attacker still has to do. A weak verifier has to be captured and cracked. A wildcard host has to be reached from somewhere. This one describes an account with nothing in the way: reach the server, know the name, you are in. There is no step in between, which is why it outranks the rest of the family.

The name is not a secret. It appears in configuration files, in deployment manifests, in the error message a misconfigured client prints. Treating it as one is the assumption this finding exists to remove.

Bad

-- MySQL: a password plugin with nothing stored under it.
-- The server accepts this and treats an empty credential as a valid login.
CREATE USER 'reporting'@'%' IDENTIFIED WITH caching_sha2_password;

Good

-- Either give it a password…
ALTER USER 'reporting'@'%' IDENTIFIED BY 'a real secret';

-- …or say out loud that the credential lives elsewhere, which is a
-- different arrangement and not an empty password.
ALTER USER 'reporting'@'localhost' IDENTIFIED WITH auth_socket;

The two fixes are not interchangeable, and choosing between them is a decision rather than a technique: is this account supposed to authenticate with a password, or with something the database does not hold? An empty password under a password plugin is neither — it is the first arrangement, left unfinished.

Why PostgreSQL is not reported

The reading maps PostgreSQL's rolpassword IS NULL onto the same value, and on PostgreSQL that value is ordinary. A role that exists to own objects has no password by design. A role that authenticates by peer, ident or GSSAPI has none because the credential is not a password. Whether anyone can actually connect as it is decided in pg_hba.conf — a separate reading with its own rules, where SEC.AUTH.HBA_TRUST is what an open door looks like.

A rule that reported both engines would fire on most PostgreSQL databases for a state their operators chose, and it would be switched off long before it caught the MySQL case it exists for.

What is not reported

An account whose credential lives outside the database. auth_socket, PAM and LDAP accounts carry an empty credential field legitimately, because the secret is genuinely elsewhere. The reading classifies by plugin, not by the emptiness of the field, so these never reach this rule. A check written against the column instead would report every socket-authenticated account on every server — which is how a security rule earns a permanent --ignore.

The engine's own accounts. mysql.sys, mysql.session and mysql.infoschema are marked as system accounts by the reading. A finding a project cannot act on is noise however right it is.

An account whose credential state could not be read is reported as undetermined, never as an account without a password. That substitution is the one that matters most here: it would turn a locked door into an open one in the report, and send somebody to set a password on an account that already had one.