fix(security): close XFF bypass and three secret-leak paths #100
Reference in New Issue
Block a user
Delete Branch "fix/security-xff-secrets"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Four fixes hardening the secrets + rate-limit posture (the security cluster of the fresh-eyes first-cut backlog).
3a — X-Forwarded-For rate-limit bypass + memory DoS (
ratelimit.go)clientIPreturned the raw XFF header, so an attacker rotating it minted unlimited distinct limiter keys — never tripping the limit and growing the visitors map without bound. XFF is now honored only when the immediate peer is a configured trusted proxy (UPTOP_TRUSTED_PROXIES, CIDRs or bare IPs), using the right-most non-trusted hop (RFC 7239); otherwise the key is the realRemoteAddr. The visitors map is bounded with LRU eviction as defense in depth.3b — Export redaction denylist → per-provider allowlist (
server.go)The six-key denylist missed the actual credentials — the webhook URL for discord/slack/webhook/ntfy/gotify and api_key for opsgenie — exporting them in the clear.
redactByProviderkeeps only known-safe keys per provider type and redacts everything else, so unknown/new keys fail safe.3c —
ImportDataplaintext secrets (sqlstore.go)Import inserted raw
json.Marshal(settings), bypassing the encryptionAddAlert/UpdateAlertuse. It now routes throughmarshalSettings, so a restore withUPTOP_ENCRYPTION_KEYset storesenc:-prefixed ciphertext, not plaintext.3d — Alert error credential leak (
alert.go)Provider
Sendreturned the raw*url.Error, whose URL carries the secret (Telegram bot token in the path, webhook secrets in the URL); it was persisted toAlertHealth.LastErrorand shown in the TUI.sanitizeErrorstrips the URL, keeping the operation + underlying cause.Tests
Trusted/untrusted XFF + spoofed-bypass + map-bound, the allowlist per provider, encrypted-on-import round-trip, URL-stripped errors. Full suite green under
-race; golangci-lint clean locally. README documentsUPTOP_TRUSTED_PROXIES+ reverse-proxy setup.Phase 3 of the fresh-eyes first-cut backlog (builds on #98, #99).