fix: enforce key ownership on revoke for non-admin users (IDOR)

This commit is contained in:
2026-06-29 08:38:55 +02:00
parent 21d74ebfe0
commit e56d97f808
2 changed files with 31 additions and 0 deletions

View File

@@ -171,6 +171,21 @@ func (a *API) adminRevokeKey(w http.ResponseWriter, r *http.Request) {
writeError(w, http.StatusBadRequest, "invalid id")
return
}
au := userFrom(r.Context())
if au != nil && !au.IsAdmin {
// Non-admins may only revoke their own keys.
key, err := a.Store.GetVirtualKeyByID(r.Context(), id)
if err != nil {
writeError(w, http.StatusInternalServerError, err.Error())
return
}
if key == nil || key.UserID == nil || *key.UserID != au.User.ID {
writeError(w, http.StatusNotFound, "key not found")
return
}
}
if err := a.Store.RevokeVirtualKey(r.Context(), id); err != nil {
writeError(w, http.StatusInternalServerError, err.Error())
return

View File

@@ -115,6 +115,22 @@ func (s *Store) ListVirtualKeys(ctx context.Context, userID *uuid.UUID) ([]Virtu
return out, rows.Err()
}
// GetVirtualKeyByID returns a key's ownership info by primary key. Returns (nil, nil) when not found.
func (s *Store) GetVirtualKeyByID(ctx context.Context, id uuid.UUID) (*VirtualKey, error) {
var k VirtualKey
err := s.pool.QueryRow(ctx, `
SELECT id, COALESCE(name,''), key_prefix, type, user_id, allow_all_models, group_id, expires_at, revoked_at
FROM virtual_keys WHERE id = $1`, id,
).Scan(&k.ID, &k.Name, &k.KeyPrefix, &k.Type, &k.UserID, &k.AllowAllModels, &k.GroupID, &k.ExpiresAt, &k.RevokedAt)
if errors.Is(err, pgx.ErrNoRows) {
return nil, nil
}
if err != nil {
return nil, err
}
return &k, nil
}
func (s *Store) RevokeVirtualKey(ctx context.Context, id uuid.UUID) error {
_, err := s.pool.Exec(ctx, `UPDATE virtual_keys SET revoked_at = now() WHERE id = $1 AND revoked_at IS NULL`, id)
return err