Skip to content

Commit 43add90

Browse files
christianmatclaude
andauthored
fix: resolve cross-workspace IDOR in workspace management endpoints (#47)
Use getWorkspace(request) to scope GET/PUT/DELETE operations to the authenticated workspace instead of accepting arbitrary workspaceId from URL params. This matches the secure pattern used by events and webhooks controllers. Closes #46 Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 752e1ab commit 43add90

1 file changed

Lines changed: 14 additions & 20 deletions

File tree

apps/trench/src/workspaces/workspaces.controller.ts

Lines changed: 14 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,16 @@ import {
44
Body,
55
UseGuards,
66
Delete,
7-
Param,
87
Put,
9-
NotFoundException,
108
Get,
9+
Request,
1110
} from '@nestjs/common'
1211

1312
import { AdminApiGuard } from 'src/middlewares/admin-api.guard'
1413
import { WorkspacesService } from 'src/workspaces/workspaces.service'
1514
import { CreateWorkspaceDto, Workspace } from 'src/workspaces/workspaces.interface'
1615
import { ApiOperation, ApiResponse } from '@nestjs/swagger'
16+
import { getWorkspace } from 'src/common/request'
1717

1818
@Controller('workspaces')
1919
@UseGuards(AdminApiGuard)
@@ -33,45 +33,39 @@ export class WorkspacesController {
3333
return newWorkspace
3434
}
3535

36-
@Delete(':workspaceId')
37-
async delete(@Param('workspaceId') workspaceId: string) {
38-
await this.workspacesService.deleteWorkspace(workspaceId)
36+
@Delete()
37+
async delete(@Request() request: Request) {
38+
const workspace = getWorkspace(request)
39+
await this.workspacesService.deleteWorkspace(workspace.workspaceId)
3940
}
4041

41-
@Put(':workspaceId')
42+
@Put()
4243
@ApiOperation({ summary: 'Update a workspace' })
4344
@ApiResponse({
4445
status: 200,
4546
description:
4647
'The workspace has been successfully updated. Requires private API key in Bearer token.',
4748
type: Workspace,
4849
})
49-
async update(
50-
@Param('workspaceId') workspaceId: string,
51-
@Body() updateWorkspaceDto: CreateWorkspaceDto
52-
) {
53-
// Assuming the method name should be 'updateWorkspace' based on the error
50+
async update(@Request() request: Request, @Body() updateWorkspaceDto: CreateWorkspaceDto) {
51+
const workspace = getWorkspace(request)
5452
const updatedWorkspace = await this.workspacesService.updateWorkspace(
55-
workspaceId,
53+
workspace.workspaceId,
5654
updateWorkspaceDto
5755
)
5856

5957
return updatedWorkspace
6058
}
6159

62-
@Get(':workspaceId')
63-
@ApiOperation({ summary: 'Get a workspace by ID' })
60+
@Get()
61+
@ApiOperation({ summary: 'Get the authenticated workspace' })
6462
@ApiResponse({
6563
status: 200,
6664
description: 'The workspace has been successfully retrieved.',
6765
type: Workspace,
6866
})
69-
async getById(@Param('workspaceId') workspaceId: string) {
70-
const workspace = await this.workspacesService.getWorkspaceById(workspaceId)
71-
72-
if (!workspace) {
73-
throw new NotFoundException('Workspace not found')
74-
}
67+
async getById(@Request() request: Request) {
68+
const workspace = getWorkspace(request)
7569

7670
return workspace
7771
}

0 commit comments

Comments
 (0)