Skip to content

fix(cards): validate platformLink ownership before creating card links#183

Open
Ridanshi wants to merge 2 commits into
Dev-Card:mainfrom
Ridanshi:fix/card-link-ownership
Open

fix(cards): validate platformLink ownership before creating card links#183
Ridanshi wants to merge 2 commits into
Dev-Card:mainfrom
Ridanshi:fix/card-link-ownership

Conversation

@Ridanshi
Copy link
Copy Markdown

@Ridanshi Ridanshi commented May 19, 2026

Summary

Fixes an IDOR vulnerability where authenticated users could attach another user's platform links to their own DevCard profile by supplying arbitrary platformLink IDs.

Previously, the backend trusted client-provided linkIds and created/updated CardLink records without validating ownership.

This allowed users to:

  • fetch another user's public profile,
  • obtain exposed platform link IDs,
  • attach those links to their own cards,
  • impersonate another user's verified social profiles.

Fix

Added strict ownership validation before creating or updating CardLink records.

The implementation now:

  • fetches all supplied linkIds,
  • verifies every link belongs to the authenticated user,
  • rejects foreign IDs with 403 Forbidden,
  • prevents any write from occurring on validation failure.

Validation is now enforced for:

  • POST /api/cards
  • PUT /api/cards/:id

No schema changes or API contract changes were introduced.


Testing

Added focused authorization tests covering:

  • owned links succeed,
  • foreign links are rejected,
  • mixed owned/foreign IDs are rejected,
  • update route validation,
  • empty linkIds,
  • prevention of partial writes on validation failure.

Also verified:

  • existing valid card flows remain unaffected,
  • sync behavior remains unchanged,
  • no regressions introduced in unrelated routes.

Security Impact

This patch restores proper ownership enforcement for platform link attachment flows and prevents profile impersonation through unauthorized link association.

Closes #149

@Harxhit Harxhit added the gssoc:approved Required label for every approved PR. Gives the base +50 points and enables contribution tracking. label May 19, 2026
@Harxhit
Copy link
Copy Markdown
Collaborator

Harxhit commented May 19, 2026

Hey, @Ridanshi could please mention the issue it closes in the PR description.

@ShantKhatri ShantKhatri self-requested a review May 20, 2026 09:36
@Ridanshi
Copy link
Copy Markdown
Author

Sure, thanks for pointing it out. I’ve updated the PR description to explicitly mention the linked issue and added the closing reference (Closes #149).

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Error handing can be better for DB logic.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the review. I’ll improve the DB-side error handling around the ownership validation flow and update the PR with a cleaner failure-handling path shortly.

Ridanshi added 2 commits May 20, 2026 17:54
POST /api/cards and PUT /api/cards/:id accepted arbitrary platformLink IDs
without verifying they belong to the authenticated user. Because platformLink
IDs are exposed in the public profile API, any authenticated user could attach
another user's verified social links to their own card, enabling impersonation.

Add a pre-flight ownership check before each CardLink write. A single indexed
query confirms every requested ID exists with userId = current user. If the
count does not match, the request is rejected with 403 before any write occurs.

Covered by new tests in src/__tests__/cards.test.ts.
Following reviewer feedback on the IDOR ownership-validation PR:

- Wrap all five route handlers in try/catch so unexpected DB exceptions
  always return { error: 'Internal server error' } rather than leaking a
  raw 500 from Fastify's default error handler.

- Replace the bare deleteMany + createMany pair in PUT /cards/:id with a
  Prisma \ call. Previously a failed createMany after a
  successful deleteMany left the card with no links (partial write).
  The transaction rolls both operations back atomically on any failure.

- Replace the bare updateMany + update pair in PUT /cards/:id/default
  with a \ for the same reason: if the second write failed the
  user had zero default cards until the next successful update.

- Add structured app.log.error({ err }) calls in every catch block so
  DB failures are observable in logs without exposing internals to clients.

Tests added (cards.test.ts):
- DB error during ownership validation -> 500, no write attempted
- DB error during card.count / card.create -> 500
- DB error during card.findFirst in PUT -> 500
- Transaction failure mid-flight (createMany throws) -> 500, card retains
  existing links
- DELETE: card.delete throws -> 500
- PUT /default: transaction failure (update throws after updateMany) -> 500
- PUT /default: success path verifies both ops run inside \
- PUT /:id: success path verifies deleteMany + createMany inside \
@Ridanshi Ridanshi force-pushed the fix/card-link-ownership branch from b96c782 to 8da2ea1 Compare May 20, 2026 12:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

design gssoc:approved Required label for every approved PR. Gives the base +50 points and enables contribution tracking. UX

Projects

None yet

Development

Successfully merging this pull request may close these issues.

IDOR: users can attach another user's platform links to their own cards

2 participants