Skip to content

Multiple authorization bypass and IDOR vulnerabilities in API #517

@lighthousekeeper1212

Description

@lighthousekeeper1212

Summary

Multiple authorization and IDOR (Insecure Direct Object Reference) vulnerabilities were found across the Peppermint API. Several sensitive configuration endpoints lack admin permission checks, and multiple data-access endpoints don't scope queries to the authenticated user.

Findings

1. HIGH - SSO/OIDC/OAuth Configuration Modification (No Admin Check)

Endpoints:

  • POST /api/v1/config/authentication/oidc/update
  • POST /api/v1/config/authentication/oauth/update
  • DELETE /api/v1/config/authentication

File: apps/api/src/controllers/config.ts (lines 54-189)

These endpoints have no requirePermission() or admin check. Any authenticated user (including external users) can enable SSO pointing to an attacker-controlled OIDC/OAuth provider, or delete all SSO configuration.

Secure sibling: PATCH /api/v1/config/toggle-roles (line 391) has both requirePermission(["settings::manage"]) AND explicit session?.isAdmin check.

2. HIGH - SMTP Email Configuration (No Admin Check)

Endpoints: PUT /api/v1/config/email, DELETE /api/v1/config/email

File: apps/api/src/controllers/config.ts (lines 243-388)

No admin/permission checks. Any user can redirect outgoing email through an attacker-controlled SMTP server.

3. HIGH - Cross-User Comment Deletion IDOR

Endpoint: POST /api/v1/ticket/comment/delete
File: apps/api/src/controllers/ticket.ts (lines 695-713)

await prisma.comment.delete({ where: { id: id } });

No user ownership check. Compare with notebook delete (notebook.ts:83) which correctly scopes: where: { id, userId: user!.id }.

4. HIGH - Force-Logout Any User IDOR

Endpoint: GET /api/v1/auth/user/:id/logout
File: apps/api/src/controllers/auth.ts (lines 932-943)

await prisma.session.deleteMany({ where: { userId: id } });

Deletes all sessions for any user ID in URL. Compare with session revocation (DELETE /api/v1/auth/sessions/:sessionId, line 1029) which correctly scopes to userId: currentUser.id.

5. MEDIUM - External User Ticket Read Bypass

Endpoint: GET /api/v1/ticket/:id
File: apps/api/src/controllers/ticket.ts (lines 249-269)

Returns full ticket details without user scoping. External users can access any ticket. Compare with external user listing (line 931) which correctly uses where: { email: user!.email }.

6. MEDIUM - Email Queue Config (No Admin Check)

Endpoints: POST /api/v1/email-queue/create, DELETE /api/v1/email-queue/delete
File: apps/api/src/controllers/queue.ts

7. LOW - Time Tracking User Attribution IDOR

Endpoint: POST /api/v1/time/new
File: apps/api/src/controllers/time.ts (lines 6-27)

userId from request body instead of session. Compare with notebook create (notebook.ts:21) which uses userId: user!.id.

Recommended Fix

  1. Add requirePermission(["settings::manage"]) + admin check to config endpoints (SSO, SMTP, email queue)
  2. Scope comment delete with userId: user!.id
  3. Verify :id matches authenticated user on logout
  4. Scope ticket reads for external users
  5. Use session user ID for time tracking

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions