fix: broken ownership check in environment secret delete/update (crash + authz bypass)#3729
Draft
cursor[bot] wants to merge 1 commit intodevelopfrom
Draft
fix: broken ownership check in environment secret delete/update (crash + authz bypass)#3729cursor[bot] wants to merge 1 commit intodevelopfrom
cursor[bot] wants to merge 1 commit intodevelopfrom
Conversation
The ownership check for environment secrets used a logically inverted condition that was both a nil-pointer crash and an authorization bypass: if key.EnvironmentID == nil && *key.EnvironmentID == env.ID Two critical issues: 1. Nil dereference panic: when EnvironmentID is nil, the left side of && is true, so Go evaluates *key.EnvironmentID which crashes the server. 2. Authorization bypass: when EnvironmentID is non-nil, the left side is false, so && short-circuits and the entire guard is never triggered. This allows any user to delete or update access keys belonging to other environments within the same project. Fix: change to 'key.EnvironmentID == nil || *key.EnvironmentID != env.ID' which correctly rejects operations when the key has no environment or belongs to a different environment. Also fixed the error message that was appending nil to the errors slice. Co-authored-by: Denis Gukov <fiftin@outlook.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Bug and Impact
The ownership guard in
updateEnvironmentSecrets(used for both delete and update operations on environment secrets) contained a logically broken condition introduced in commit84d9a735:This has two critical effects:
Nil pointer dereference (server crash): When
key.EnvironmentIDisnil, the left side of&&evaluates totrue, causing Go to dereference the nil pointer on the right side. This panics and crashes the HTTP handler.Authorization bypass: When
key.EnvironmentIDis non-nil, the left side isfalse, so&&short-circuits and the entire guard is never triggered. This means any project member can delete or modify access keys belonging to other environments in the same project by sending a crafted update/delete request with the target key ID.Concrete trigger scenario
A user with access to Environment A sends an update-environment request with a secret operation referencing a key ID that belongs to Environment B. The ownership check (meant to reject this) is bypassed because the condition always evaluates to
false. The key from Environment B is then deleted or overwritten.Root Cause
The condition
key.EnvironmentID == nil && *key.EnvironmentID == env.IDshould have beenkey.EnvironmentID == nil || *key.EnvironmentID != env.ID. The original intent was "reject if the key has no environment or belongs to a different environment," but&&with==inverts the logic entirely.Additionally, the error-appending line
errors = append(errors, err)was appendingnil(sinceGetAccessKeyhad succeeded at that point).Fix
&&to||and==to!=in both the delete and update branchesValidation
api/projects/pass