Skip to content

Commit 4dee0db

Browse files
committed
fix(plane): reject dot-segment IDs in request paths
encodeURIComponent leaves . and .. intact, so an ID of .. collapsed the URL onto the parent resource (a work item delete could target its project). Every slug and ID segment now goes through validatePathSegment.
1 parent 2c54169 commit 4dee0db

14 files changed

Lines changed: 66 additions & 19 deletions

‎apps/sim/lib/internal/plane/operations.ts‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import {
2323
mapPlaneAttachment,
2424
normalizePlaneBaseUrl,
2525
planeHeaders,
26+
planePathSegment,
2627
planeWorkItemUrl,
2728
} from '@/tools/plane/utils'
2829

@@ -131,7 +132,7 @@ async function discardPendingAttachment(
131132
) {
132133
try {
133134
const response = await planeRequest(
134-
planeWorkItemUrl(input, `attachments/${encodeURIComponent(assetId)}/`),
135+
planeWorkItemUrl(input, `attachments/${planePathSegment(assetId, 'attachmentId')}/`),
135136
{ method: 'DELETE', apiKey: input.apiKey },
136137
signal
137138
)
@@ -256,7 +257,7 @@ export async function executePlaneUploadAttachment(
256257
await uploaded.body?.cancel().catch(() => {})
257258

258259
const confirmed = await planeRequest(
259-
planeWorkItemUrl(input, `attachments/${encodeURIComponent(ticket.assetId)}/`),
260+
planeWorkItemUrl(input, `attachments/${planePathSegment(ticket.assetId, 'attachmentId')}/`),
260261
{ method: 'PATCH', apiKey: input.apiKey, body: { is_uploaded: true } },
261262
context.signal
262263
)

‎apps/sim/tools/plane/add_work_items_to_cycle.ts‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,10 @@ export const planeAddWorkItemsToCycleTool: ToolConfig<
4242

4343
request: {
4444
url: (params) =>
45-
planeProjectUrl(params, `cycles/${planePathSegment(params.cycleId)}/cycle-issues/`),
45+
planeProjectUrl(
46+
params,
47+
`cycles/${planePathSegment(params.cycleId, 'cycleId')}/cycle-issues/`
48+
),
4649
method: 'POST',
4750
headers: planeHeaders,
4851
body: (params) => {

‎apps/sim/tools/plane/add_work_items_to_module.ts‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,10 @@ export const planeAddWorkItemsToModuleTool: ToolConfig<
4444

4545
request: {
4646
url: (params) =>
47-
planeProjectUrl(params, `modules/${planePathSegment(params.moduleId)}/module-issues/`),
47+
planeProjectUrl(
48+
params,
49+
`modules/${planePathSegment(params.moduleId, 'moduleId')}/module-issues/`
50+
),
4851
method: 'POST',
4952
headers: planeHeaders,
5053
body: (params) => {

‎apps/sim/tools/plane/delete_attachment.ts‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,10 @@ export const planeDeleteAttachmentTool: ToolConfig<
3434

3535
request: {
3636
url: (params) =>
37-
planeWorkItemUrl(params, `attachments/${planePathSegment(params.attachmentId)}/`),
37+
planeWorkItemUrl(
38+
params,
39+
`attachments/${planePathSegment(params.attachmentId, 'attachmentId')}/`
40+
),
3841
method: 'DELETE',
3942
headers: planeHeaders,
4043
},

‎apps/sim/tools/plane/delete_comment.ts‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ export const planeDeleteCommentTool: ToolConfig<PlaneDeleteCommentParams, PlaneD
3030
},
3131

3232
request: {
33-
url: (params) => planeWorkItemUrl(params, `comments/${planePathSegment(params.commentId)}/`),
33+
url: (params) =>
34+
planeWorkItemUrl(params, `comments/${planePathSegment(params.commentId, 'commentId')}/`),
3435
method: 'DELETE',
3536
headers: planeHeaders,
3637
},

‎apps/sim/tools/plane/delete_link.ts‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ export const planeDeleteLinkTool: ToolConfig<PlaneDeleteLinkParams, PlaneDeleteR
3030
},
3131

3232
request: {
33-
url: (params) => planeWorkItemUrl(params, `links/${planePathSegment(params.linkId)}/`),
33+
url: (params) =>
34+
planeWorkItemUrl(params, `links/${planePathSegment(params.linkId, 'linkId')}/`),
3435
method: 'DELETE',
3536
headers: planeHeaders,
3637
},

‎apps/sim/tools/plane/delete_work_item.ts‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ export const planeDeleteWorkItemTool: ToolConfig<PlaneDeleteWorkItemParams, Plan
2525
},
2626

2727
request: {
28-
url: (params) => planeProjectUrl(params, `work-items/${planePathSegment(params.workItemId)}/`),
28+
url: (params) =>
29+
planeProjectUrl(params, `work-items/${planePathSegment(params.workItemId, 'workItemId')}/`),
2930
method: 'DELETE',
3031
headers: planeHeaders,
3132
},

‎apps/sim/tools/plane/download_attachment.ts‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,10 @@ export const planeDownloadAttachmentTool: ToolConfig<
4242

4343
request: {
4444
url: (params) =>
45-
planeWorkItemUrl(params, `attachments/${planePathSegment(params.attachmentId)}/`),
45+
planeWorkItemUrl(
46+
params,
47+
`attachments/${planePathSegment(params.attachmentId, 'attachmentId')}/`
48+
),
4649
method: 'GET',
4750
headers: (params) => ({ 'X-API-Key': params.apiKey.trim(), Accept: '*/*' }),
4851
responseType: 'binary',

‎apps/sim/tools/plane/get_project.ts‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ export const planeGetProjectTool: ToolConfig<PlaneGetProjectParams, PlaneProject
2424
},
2525

2626
request: {
27-
url: (params) => planeWorkspaceUrl(params, `projects/${planePathSegment(params.projectId)}/`),
27+
url: (params) =>
28+
planeWorkspaceUrl(params, `projects/${planePathSegment(params.projectId, 'projectId')}/`),
2829
method: 'GET',
2930
headers: planeHeaders,
3031
},

‎apps/sim/tools/plane/get_work_item.ts‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ export const planeGetWorkItemTool: ToolConfig<PlaneGetWorkItemParams, PlaneWorkI
2626
},
2727

2828
request: {
29-
url: (params) => planeProjectUrl(params, `work-items/${planePathSegment(params.workItemId)}/`),
29+
url: (params) =>
30+
planeProjectUrl(params, `work-items/${planePathSegment(params.workItemId, 'workItemId')}/`),
3031
method: 'GET',
3132
headers: planeHeaders,
3233
},

0 commit comments

Comments
 (0)