Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
fix(knowledge): enforce connector chunk readonly on server side
  • Loading branch information
waleedlatif1 committed Mar 6, 2026
commit 70e286fdacf86775eabe297bc30e41cac220c24a
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,16 @@ export async function PUT(
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
}

if (accessCheck.document?.connectorId) {
logger.warn(
`[${requestId}] User ${session.user.id} attempted to update chunk on connector-synced document: Doc=${documentId}`
)
return NextResponse.json(
{ error: 'Chunks from connector-synced documents are read-only' },
{ status: 403 }
)
}

const body = await req.json()

try {
Expand Down Expand Up @@ -167,6 +177,16 @@ export async function DELETE(
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
}

if (accessCheck.document?.connectorId) {
logger.warn(
`[${requestId}] User ${session.user.id} attempted to delete chunk on connector-synced document: Doc=${documentId}`
)
return NextResponse.json(
{ error: 'Chunks from connector-synced documents are read-only' },
{ status: 403 }
)
}

await deleteChunk(chunkId, documentId, requestId)

logger.info(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,16 @@ export async function POST(
return NextResponse.json({ error: 'Document not found' }, { status: 404 })
}

if (doc.connectorId) {
logger.warn(
`[${requestId}] User ${userId} attempted to create chunk on connector-synced document: Doc=${documentId}`
)
return NextResponse.json(
{ error: 'Chunks from connector-synced documents are read-only' },
{ status: 403 }
)
}

// Allow manual chunk creation even if document is not fully processed
// but it should exist and not be in failed state
if (doc.processingStatus === 'failed') {
Expand Down Expand Up @@ -283,6 +293,16 @@ export async function PATCH(
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
}

if (accessCheck.document?.connectorId) {
logger.warn(
`[${requestId}] User ${userId} attempted batch chunk operation on connector-synced document: Doc=${documentId}`
)
return NextResponse.json(
{ error: 'Chunks from connector-synced documents are read-only' },
{ status: 403 }
)
}

const body = await req.json()

try {
Expand Down
4 changes: 4 additions & 0 deletions apps/sim/app/api/knowledge/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ export interface DocumentData {
boolean1?: boolean | null
boolean2?: boolean | null
boolean3?: boolean | null
// Connector fields
connectorId?: string | null
}

export interface EmbeddingData {
Expand Down Expand Up @@ -283,6 +285,8 @@ export async function checkDocumentWriteAccess(
boolean1: document.boolean1,
boolean2: document.boolean2,
boolean3: document.boolean3,
// Connector fields
connectorId: document.connectorId,
})
.from(document)
.where(and(eq(document.id, documentId), isNull(document.deletedAt)))
Expand Down