SEC.CFG.LOCAL_INFILE — The server may ask the client for a file
- Category: security
- Severity: medium
- Level: 0
- Confidence: deterministic
- Downtime class: none — the finding is about a server setting, not about a statement
- Stability: stable
- Suites: audit
- Applies to: MySQL 8.4
Which way it points
LOAD DATA LOCAL INFILE does not read a file on the server.
The server sends the client a request naming a path. A compliant client reads that path off its own disk and uploads the contents. The client does not choose the path — it is told one.
So a server that is compromised, or one an application was pointed at by mistake, can ask for an
.env, a key file or /etc/passwd, and a client with the capability enabled hands it over. Your
application does not have to run a single LOAD DATA statement for this to happen: the request comes
from the other end of the connection.
This is why a reader who takes the statement name at face value reaches the wrong conclusion — "we never call LOAD DATA, so this cannot touch us" — and it is the whole reason the rule exists.
Why medium
Exploiting it needs a hostile or hijacked server, which is a larger precondition than most findings in this suite carry.
What it does not need is any privilege on the account. The capability is negotiated at connection
time, not granted — so no GRANT anywhere makes a difference to it.
What this rule cannot see
It reads the server's side of the negotiation. A client can refuse independently: PHP's
mysqli.allow_local_infile and PDO's PDO::MYSQL_ATTR_LOCAL_INFILE both default to off on current
builds. The finding says the server would ask, not that anybody would answer.
What it looks like
# my.cnf: the server may ask the client to send it a file.
local_infile = ON
What to do about it
# Off is the vendor default on 8.4, and costs an application nothing.
local_infile = OFF
A data-import job that genuinely uses LOAD DATA LOCAL INFILE is the one case worth checking first —
it can be enabled for the single session that needs it.
The variable is GLOBAL-only and dynamic: SET GLOBAL local_infile = OFF takes effect without
downtime, but no individual session may set it.
Not the same as SEC.CFG.SECURE_FILE_PRIV
They point in opposite directions and neither implies the other. secure_file_priv bounds what the
server may read and write on its disk; local_infile decides whether the server may ask the
client for a file.