Skip to main content

SEC.AUTH.ROLE_WILDCARD_HOST — The account may connect from any host

  • Category: security
  • Severity: medium
  • 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

The host is not a label​

A MySQL account is a name and a host pattern, and the server matches an incoming connection against that pattern before it considers a password at all. 'deploy'@'%' and 'deploy'@'10.0.0.5' are two different accounts, and the second one refuses a connection from anywhere else without ever looking at a credential.

That makes the host half a real control rather than documentation — and it is the control most easily left at its widest, because % is what every quick-start snippet uses.

Bad​

-- Reachable from every address the server has.
CREATE USER 'deploy'@'%' IDENTIFIED BY 'a real secret';

Good​

-- Reachable from the network the client actually comes from.
CREATE USER 'deploy'@'10.0.0.0/24' IDENTIFIED BY 'a real secret';

Which patterns count​

% and _ are wildcards in the host half, and they do not all widen alike:

HostWhat it admitsReported
%, or only wildcards and dots such as %.%.%.%every addresshere, or at high by the sibling when the account is privileged
a pattern over names, such as %.example.comevery host whose name matches ithere, whatever the account holds
an address pattern, such as 10.0.0.%an address rangeno
_ without %, such as db_host.internalthe names that differ from it in that one placeno

A name pattern is matched against the name the client's address resolves to, so what admits a client is the DNS behind those names. An address pattern is not an open host at all: MySQL matches an IP wildcard value only against IP addresses, never against a host name. The MySQL 8.4 manual lists % and _ in a host value as deprecated, which is why the example above uses CIDR notation.

Why medium, and why this is not an accusation​

A wildcard host is the correct choice for some accounts. Monitoring agents reach a server from addresses nobody wants to enumerate; a container platform can reassign a client's address on every deploy. A replication account is not among them here: REPLICATION SLAVE reads every change the server records, so an open replication account is the sibling rule's. Reporting this loudly would put a permanent line in the report of every deployment that has a good reason for it — and those tend to be the deployments with the most accounts.

So what this finding gives you is the list, not a verdict on each entry: the accounts for which "reachable from anywhere" should have been a decision somebody made on purpose.

Where it is not a decision but an oversight, the account usually also holds privileges it does not need — and that is a different finding at a different weight: SEC.AUTH.ROLE_WILDCARD_HOST_PRIVILEGED.

What is not reported​

PostgreSQL, entirely — and not because of an engine check. A PostgreSQL role carries no host at all; where a connection may come from is decided in pg_hba.conf, which SEC.AUTH.HBA_OPEN_CIDR reads. The fact this rule judges does not exist there, so it is silent by construction.

The engine's own accounts, which ship bound to localhost anyway.

An address range, such as 10.0.0.%, and an underscore in a host name, such as db_host.internal. The table above says why.

An account whose record could not be read is reported as undetermined, on both rules of the pair rather than quietly on the milder one.