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.
The fix material this rule carries
A finding from this rule carries a payload whose strategy is none: this rule has looked,
and there is no safe standard sequence. That is a conclusion rather than an omission — a
finding with no payload at all says only that nobody wrote one.
The payload is material for you or an agent to apply. SQLens writes no migration and runs no DDL. See the remediation payload for every field, the placeholder semantics, and the version rules a consumer has to follow.