security: harden auth, SSO, path handling, access control#50
Merged
Conversation
HIGH - CLI auth session hijacking (CVE-like): Require explicit user consent before completing CLI auth flow. Previously the signin page auto-submitted any cli_session param, allowing an attacker to mint a victim-scoped API token. HIGH - OIDC SSO callback seat bypass + missing route: Add maxSeats enforcement before creating TeamMember via SSO. Create the missing /auth/sso-complete page that the OIDC callback redirects to. MEDIUM - CLI pull path traversal: Add safePath() guard to reject ../ segments in repository_path. Server-side: strip traversal patterns from repository_path on save. MEDIUM - Multi-team access resolution: Replace findFirst (returns arbitrary team) with findUnique on the composite teamId_userId key for TEAM visibility checks. Return all team memberships from billing/status endpoint. LOW - Download analytics auth check: Require ownership or team membership to view download stats for non-public blueprints.
… stats and paths - Add SSO CredentialsProvider to auth.ts with HMAC signature validation - Pass teamId through sso-complete page to complete the OIDC flow - Move seat-limit check before user creation in SSO callback - Strip bp_ prefix on user template DB queries in download stats route - Apply path traversal sanitization to all repositoryPath write paths - Fix multi-team support in team settings page and dashboard route
…nload IDs - Replace replayable HMAC-signed SSO URL with one-time nonce stored in VerificationToken (5-minute expiry, consumed on first use) - Fix team settings page using wrong role for invitation loading - Expose all teams + per-team blueprints from dashboard route - Strip sys_ prefix for system template download counter updates
- Wrap SSO seat-limit check + user/membership creation in a serializable Prisma transaction to prevent concurrent logins exceeding maxSeats - Create page now fetches all teams from billing/status and shows a team selector when user belongs to multiple teams - Submit uses selectedTeamId instead of hardcoded first-team fallback
- Wrap invitation acceptance seat-limit check + membership creation in a serializable Prisma transaction (same pattern as SSO callback) - Dashboard now renders team banners and blueprints for all teams, not just the first membership - Fix tx parameter types and user nullability in SSO callback
- Both SSO callback and invitation acceptance now retry up to 3 times on Prisma P2034 (serialization conflict) instead of bubbling a 500 - "Share with Team" CTA passes teamId in URL query param - Create page reads teamId from URL, preselects the target team and auto-sets visibility to TEAM when linked from a specific team panel
- Invitation acceptance now re-checks teamMember inside the serializable transaction, so parallel duplicate submissions are idempotent instead of hitting the unique constraint - Empty-state "Share with Team" button now passes teamId query param (matching the header CTA fix from previous commit)
…g on auth redirect - Both SSO and invitation retry loops now catch P2002 (unique constraint violation from concurrent inserts) alongside P2034 serialization errors - Create page preserves full URL including ?teamId= when redirecting unauthenticated users to sign-in
The regex-based .replace(/\.\.[/\\]/g, "") was bypassable (e.g. ....// becomes ../ after one pass). Replace with posix.normalize() plus prefix check that rejects any path traversal after normalization. Fixes CodeQL high-severity alerts on PR #50.
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.
Summary
Addresses 5 security findings from a breadth-first review of auth/session, CLI flows, teams/SSO, and content routes.
HIGH
cli_sessionquery param as soon as the browser was authenticated, allowing an attacker to trick a victim into minting an API token for the attacker's CLI session. Fixed by adding an explicit "Authorize CLI" consent screen.TeamMemberwithout checkingmaxSeats. Also redirected to non-existent/auth/sso-complete. Fixed both: added seat enforcement and created the missing page.MEDIUM
repository_pathfrom the cloud was joined directly with the output directory, allowing../escape. AddedsafePath()guard in CLI and server-side sanitization.findFirst({ where: { userId } })returning an arbitrary team. Replaced withfindUniqueon the compositeteamId_userIdkey. Billing endpoint now returns all memberships.LOW
Files changed
src/app/auth/signin/page.tsx— CLI consent screensrc/app/api/auth/sso/callback/oidc/route.ts— maxSeats checksrc/app/auth/sso-complete/page.tsx— new SSO completion pagecli/src/commands/pull.ts— safePath guardsrc/app/api/v1/blueprints/route.ts— sanitize repository_pathsrc/lib/data/templates.ts— multi-team access fixsrc/app/api/billing/status/route.ts— return all teamssrc/app/api/blueprints/[id]/download/route.ts— auth check on statsTest plan
lynxp pullwith../in repository_path: verify blocked/api/blueprints/bp_xxx/download: verify 401