diff --git a/.jules/sentinel.md b/.jules/sentinel.md new file mode 100644 index 00000000..a75814c0 --- /dev/null +++ b/.jules/sentinel.md @@ -0,0 +1,4 @@ +## 2025-05-22 - [Mass Assignment in Server Actions] +**Vulnerability:** Use of object spreads (...data) in Drizzle .set() and .values() methods within Next.js Server Actions. +**Learning:** Server Actions can receive any JSON payload from the client. Using spreads directly on these inputs can allow attackers to overwrite protected fields like 'userId' or 'id', leading to data corruption or privilege escalation. +**Prevention:** Always explicitly map allowed fields from client-provided objects when performing database operations in Server Actions. diff --git a/lib/actions/calendar.ts b/lib/actions/calendar.ts index d2e4dcf9..0b57e79b 100644 --- a/lib/actions/calendar.ts +++ b/lib/actions/calendar.ts @@ -73,7 +73,15 @@ export async function saveNote(noteData: NewCalendarNote | CalendarNote): Promis try { const [updatedNote] = await db .update(calendarNotes) - .set({ ...noteData, updatedAt: new Date() }) + .set({ + chatId: noteData.chatId, + date: noteData.date, + content: noteData.content, + locationTags: noteData.locationTags, + userTags: noteData.userTags, + mapFeatureId: noteData.mapFeatureId, + updatedAt: new Date() + }) .where(and(eq(calendarNotes.id, noteData.id), eq(calendarNotes.userId, userId))) .returning(); return updatedNote; @@ -86,7 +94,15 @@ export async function saveNote(noteData: NewCalendarNote | CalendarNote): Promis try { const [newNote] = await db .insert(calendarNotes) - .values({ ...noteData, userId }) + .values({ + userId: userId, + chatId: noteData.chatId, + date: noteData.date, + content: noteData.content, + locationTags: noteData.locationTags, + userTags: noteData.userTags, + mapFeatureId: noteData.mapFeatureId, + }) .returning(); if (newNote && newNote.chatId) {