From 6eb30c7b79a34902b4ceeb2edd68d92f376f06e2 Mon Sep 17 00:00:00 2001 From: Bryan Frimin Date: Mon, 25 May 2026 23:04:44 -0700 Subject: [PATCH] Fix timing attack on signin Signed-off-by: Bryan Frimin --- pkg/iam/auth_service.go | 2 +- pkg/iam/service.go | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/pkg/iam/auth_service.go b/pkg/iam/auth_service.go index cda239131..dabefab82 100644 --- a/pkg/iam/auth_service.go +++ b/pkg/iam/auth_service.go @@ -505,7 +505,7 @@ func (s AuthService) CheckCredentials( // Perform a password comparison even when the identity does not exist to mitigate timing attacks // and prevent revealing account existence. if identity.ID == gid.Nil { - _, _ = s.hp.ComparePasswordAndHash([]byte(password+"qwertyuiop1234567890"), []byte("qwertyuiop1234567890")) + _, _ = s.hp.ComparePasswordAndHash([]byte(password), s.dummyHash) return NewInvalidCredentialsError("invalid email or password") } diff --git a/pkg/iam/service.go b/pkg/iam/service.go index 23ca728a6..396366eb7 100644 --- a/pkg/iam/service.go +++ b/pkg/iam/service.go @@ -45,6 +45,7 @@ type ( pg *pg.Client fm *filemanager.Service hp *passwdhash.Profile + dummyHash []byte baseURL string tokenSecret string disableSignup bool @@ -99,6 +100,15 @@ type ( } ) +func mustHashDummy(hp *passwdhash.Profile) []byte { + h, err := hp.HashPassword([]byte("dummy")) + if err != nil { + panic(fmt.Sprintf("cannot hash dummy password: %v", err)) + } + + return h +} + func NewService( ctx context.Context, pgClient *pg.Client, @@ -126,6 +136,7 @@ func NewService( pg: pgClient, fm: fm, hp: hp, + dummyHash: mustHashDummy(hp), baseURL: cfg.BaseURL.String(), tokenSecret: cfg.TokenSecret, disableSignup: cfg.DisableSignup,