[WEB-7877] fix(security): enforce token + auth validation on project invite accept/reject#9308
[WEB-7877] fix(security): enforce token + auth validation on project invite accept/reject#9308mguptahub wants to merge 2 commits into
Conversation
…pt/reject ProjectJoinEndpoint.post() only checked that the caller-supplied email matched the invited email — no token required, no authentication required. Anyone who knew the workspace slug, project ID, invite UUID, and invitee email could accept or reject the invitation on the invitee's behalf (GHSA-g36h-p63v-g9c7). Mirror WorkspaceJoinEndpoint.post() exactly: - Validate `token` from request body against project_invite.token (→ 403 on mismatch) - Require authenticated session (→ 401 if unauthenticated) - Validate request.user.email against project_invite.email (→ 403 on mismatch) - Remove the old request.data["email"] guard - Use project_invite.email for downstream User lookup Co-authored-by: Plane AI <noreply@plane.so>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthrough
ChangesProject Invitation Acceptance Security Hardening
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Linked to Plane Work Item(s) References This comment was auto-generated by Plane |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/api/plane/app/views/project/invite.py`:
- Line 214: The invite acceptance flow in the project invite view currently
assigns request.data["accepted"] directly in the handler, which can treat string
values like "false" as truthy and incorrectly accept invites. Update the
acceptance logic in the invite-handling method so `accepted` is parsed and
validated as a real boolean before it is saved or used to create memberships,
and make sure any non-boolean input is rejected or normalized explicitly.
- Around line 207-220: The invite acceptance flow in the project invite handler
uses a case-insensitive check on request.user.email but then re-queries User by
exact project_invite.email, which can miss the authenticated account or pick the
wrong case variant. Update the acceptance branch in the invite view to use the
already authenticated request.user (the same user validated earlier) when
creating membership-related records, rather than looking up
User.objects.filter(email=project_invite.email).first(). Ensure the later
membership writes and any related logic consistently reference that
authenticated user object.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 8743b040-043e-494c-a47d-8f2ef4fa7e3d
📒 Files selected for processing (1)
apps/api/plane/app/views/project/invite.py
- Use request.user directly instead of re-querying User by exact project_invite.email — avoids case-variant miss after the case-insensitive email check already validated the authenticated user (CR comment 1) - Validate `accepted` as a real boolean before saving — form-encoded strings like "false" are truthy and could accidentally create memberships (CR comment 2) Co-authored-by: Plane AI <noreply@plane.so>
Summary
Fixes GHSA-g36h-p63v-g9c7 — Cluster K.
ProjectJoinEndpoint.post()only validated that the caller-supplied email matched the invited email. There was no token requirement and no authentication requirement — anyone who knew the workspace slug, project ID, invite UUID, and invitee email could accept or reject a project invitation on the invitee's behalf.Changes
views/project/invite.py—ProjectJoinEndpoint.post():tokenfrom request body againstproject_invite.token→ 403 on missing or mismatched tokenrequest.user.emailagainstproject_invite.email→ 403 on mismatchrequest.data["email"]guardproject_invite.emailfor downstreamUser.objects.filter(...)lookupPattern
Mirrors
WorkspaceJoinEndpoint.post()exactly (fixed in WEB-7854 / PR #9297).Test plan
POSTwith correct token + authenticated as the invited user → accepts/declines successfullyPOSTwith wrong token → 403POSTwith no token → 403POSTunauthenticated (even with correct token) → 401POSTauthenticated as a different user (even with correct token) → 403GETstill works unauthenticated (public serializer, no token exposed)Summary by CodeRabbit