The vulnerability, CVE-2026-76081, describes an improper role revocation issue in ZITADEL, specifically an off-by-one error when multiple project roles are deleted simultaneously from User Grants on Granted Projects. This error could lead to users retaining elevated permissions.
Analysis of the provided commit 9d60e83d6faa5e7e7a5339e031cdb26e0efe4d59 reveals the core of the vulnerability in the removeRoleFromUserGrant function within internal/command/user_grant.go. The original implementation used a manual loop to remove elements from a slice (existingUserGrant.RoleKeys). When an element was removed, subsequent elements were shifted, but the loop's index was not adjusted, causing the element immediately following a removed one to be skipped. This is a classic off-by-one error in slice manipulation.
The patch addresses this by replacing the faulty manual removal loop with slices.DeleteFunc, a safer and more idiomatic Go function for removing elements from a slice based on a predicate. Additionally, the GetRemovedRoles function in internal/domain/project_grant.go was modified to return a map[string]bool instead of a []string. This change in data structure for the roles to be removed facilitates the correct and efficient removal logic in removeRoleFromUserGrant by allowing for direct lookup rather than repeated linear scans, thus preventing the off-by-one issue.
The command.Commands.removeRoleFromUserGrant function is the primary vulnerable function because it contained the direct implementation of the flawed role removal logic. The domain.GetRemovedRoles function is also identified as vulnerable because its previous return type and usage contributed to the conditions that allowed the off-by-one error to occur in the downstream removeRoleFromUserGrant function. The other changes in the commit, such as the new setup migration (cmd/setup/73.go and 73.sql) and the internal/api/grpc/management/integration_test/user_grant_test.go file, are either post-exploitation remediation or testing for the fix, not the vulnerable code itself.