Problem
AuditService.LogFiber (backend/internal/auth/audit.go) records the client IP like this:
ip := c.IP()
if xff := c.Get("X-Forwarded-For"); xff != "" {
ip = xff
}
c.IP() already resolves the forwarded header, and only when the peer is a configured trusted proxy (middleware.TrustedProxies, EnableTrustedProxyCheck). The raw read overrides that. Any client can write any value it likes into the ip column of auth_audit_logs for every login, refresh, MFA and SSO event, so an attacker can hide their address or blame someone else's. The rate limiter fixed the same pattern under audit finding F-04; the audit trail was left behind.
Also, the column is varchar(45), so a long multi-hop header (a, b, c) can fail the insert. Audit writes are best-effort (_ =), so the event is then lost without a trace.
Acceptance criteria
LogFiber records c.IP() only.
- Test: a request from an untrusted peer that sends
X-Forwarded-For: 203.0.113.9 is audited with the peer address, not 203.0.113.9.
- Test: behind a trusted proxy, the forwarded client address is recorded (this is
c.IP()'s own behaviour; the test proves it is not lost).
- No other
X-Forwarded-For read is left in backend/internal/auth. A grep is pasted in the PR.
Definition of Done
Problem
AuditService.LogFiber(backend/internal/auth/audit.go) records the client IP like this:c.IP()already resolves the forwarded header, and only when the peer is a configured trusted proxy (middleware.TrustedProxies,EnableTrustedProxyCheck). The raw read overrides that. Any client can write any value it likes into theipcolumn ofauth_audit_logsfor every login, refresh, MFA and SSO event, so an attacker can hide their address or blame someone else's. The rate limiter fixed the same pattern under audit finding F-04; the audit trail was left behind.Also, the column is
varchar(45), so a long multi-hop header (a, b, c) can fail the insert. Audit writes are best-effort (_ =), so the event is then lost without a trace.Acceptance criteria
LogFiberrecordsc.IP()only.X-Forwarded-For: 203.0.113.9is audited with the peer address, not203.0.113.9.c.IP()'s own behaviour; the test proves it is not lost).X-Forwarded-Forread is left inbackend/internal/auth. A grep is pasted in the PR.Definition of Done
go build ./... && go vet ./... && go test ./... -racegreen, output pasted.Closes.