Server side cross-site scripting In github.com/filebrowser/filebrowser/v2
Description
File Browser vulnerable to Stored Cross-site Scripting via text/template branding injection
Summary
The SPA index page in File Browser is vulnerable to Stored Cross-site Scripting (XSS) via admin-controlled branding fields. An admin who sets branding.name to a malicious payload injects persistent JavaScript that executes for ALL visitors, including unauthenticated users.
Details
http/static.go renders the SPA index.html using Go's text/template (NOT html/template) with custom delimiters [{[ and ]}]. Branding fields are inserted directly into HTML without any escaping:
// http/static.go, line 16 — imports text/template instead of html/template "text/template" // http/static.go, line 33 — branding.Name passed into template data "Name": d.settings.Branding.Name, // http/static.go, line 97 — template parsed with custom delimiters, no escaping index := template.Must(template.New("index").Delims("[{[", "]}]").Parse(string(fileContents)))...
The frontend template (frontend/public/index.html) embeds these fields directly:
<!-- frontend/public/index.html, line 16 --> [{[ if .Name -]}][{[ .Name ]}][{[ else ]}]File Browser[{[ end ]}] <!-- frontend/public/index.html, line 42 --> content="[{[ if .Color -]}][{[ .Color ]}][{[ else ]}]#2979ff[{[ end ]}]"
Since text/template performs NO HTML escaping (unlike html/template), setting branding.name to </title><script>alert(1)</script> breaks out of the <title> tag and injects arbitrary script into every page load.
Additionally, when ReCaptcha is enabled, the ReCaptchaHost field is used as:
<script src="[{[.ReCaptchaHost]}]/recaptcha/api.js"></script>
This allows loading arbitrary JavaScript from an admin-chosen origin.
No Content-Security-Policy header is set on the SPA entry point, so there is no CSP mitigation.
PoC
Below is the PoC python script that could be ran on test environment using docker compose:
services: filebrowser: image: filebrowser/filebrowser:v2.62.1 user: 0:0 ports: - "80:80"
And running this PoC python script:
import argparse import json import sys import requests BANNER = """ Stored XSS via Branding Injection PoC...
And terminal output:
root@server205:~/sec-filebrowser# python3 poc_branding_xss.py -t http://localhost -u admin -p "jhSR9z9pofv5evlX" Stored XSS via Branding Injection PoC Affected: filebrowser/filebrowser <=v2.62.1 Root cause: http/static.go uses text/template (not html/template) Branding fields rendered unescaped into SPA index.html [*] ATTACK BEGINS......
Impact
Stored XSS affecting ALL visitors including unauthenticated users
Persistent backdoor — the payload survives until branding is manually changed
Mitigation
Update Impact
Minimal update. May introduce new vulnerabilities or breaking changes.
Ecosystem | Package | Affected version | Patched versions |
|---|---|---|---|
go | 2.62.2 |
Aliases
References