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
- Add
requirePermission(["settings::manage"]) + admin check to config endpoints (SSO, SMTP, email queue)
- Scope comment delete with
userId: user!.id
- Verify
:id matches authenticated user on logout
- Scope ticket reads for external users
- Use session user ID for time tracking
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/updatePOST /api/v1/config/authentication/oauth/updateDELETE /api/v1/config/authenticationFile:
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 bothrequirePermission(["settings::manage"])AND explicitsession?.isAdmincheck.2. HIGH - SMTP Email Configuration (No Admin Check)
Endpoints:
PUT /api/v1/config/email,DELETE /api/v1/config/emailFile:
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/deleteFile:
apps/api/src/controllers/ticket.ts(lines 695-713)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/logoutFile:
apps/api/src/controllers/auth.ts(lines 932-943)Deletes all sessions for any user ID in URL. Compare with session revocation (
DELETE /api/v1/auth/sessions/:sessionId, line 1029) which correctly scopes touserId: currentUser.id.5. MEDIUM - External User Ticket Read Bypass
Endpoint:
GET /api/v1/ticket/:idFile:
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/deleteFile:
apps/api/src/controllers/queue.ts7. LOW - Time Tracking User Attribution IDOR
Endpoint:
POST /api/v1/time/newFile:
apps/api/src/controllers/time.ts(lines 6-27)userIdfrom request body instead of session. Compare with notebook create (notebook.ts:21) which usesuserId: user!.id.Recommended Fix
requirePermission(["settings::manage"])+ admin check to config endpoints (SSO, SMTP, email queue)userId: user!.id:idmatches authenticated user on logout