Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
10 changes: 10 additions & 0 deletions packages/agentflow/src/infrastructure/api/credentials.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,15 @@ describe('bindCredentialsApi', () => {
expect(mockClient.get).toHaveBeenCalledWith('/credentials', { params: { credentialName: 'openAIApi' } })
expect(result).toEqual(mockCredentials)
})

it('should not expose encryptedData in the response', async () => {
const mockCredentials = [{ id: '1', name: 'My OpenAI Key', credentialName: 'openAIApi' }]
;(mockClient.get as jest.Mock).mockResolvedValue({ data: mockCredentials })

const result = await api.getCredentialsByName('openAIApi')
for (const credential of result) {
expect(credential).not.toHaveProperty('encryptedData')
}
})
})
})
23 changes: 20 additions & 3 deletions packages/server/src/controllers/tools/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,17 @@ const createTool = async (req: Request, res: Response, next: NextFunction) => {
throw new InternalFlowiseError(StatusCodes.NOT_FOUND, `Error: toolsController.createTool - workspace ${workspaceId} not found!`)
}
const body = req.body
body.workspaceId = workspaceId
// Explicit allowlist — id/workspaceId/timestamps must not be overrideable by client
const toolBody: Record<string, unknown> = {}
if (body.name !== undefined) toolBody.name = body.name
if (body.description !== undefined) toolBody.description = body.description
if (body.color !== undefined) toolBody.color = body.color
if (body.iconSrc !== undefined) toolBody.iconSrc = body.iconSrc
if (body.schema !== undefined) toolBody.schema = body.schema
if (body.func !== undefined) toolBody.func = body.func
toolBody.workspaceId = workspaceId

const apiResponse = await toolsService.createTool(body, orgId)
const apiResponse = await toolsService.createTool(toolBody, orgId)
return res.json(apiResponse)
} catch (error) {
next(error)
Expand Down Expand Up @@ -84,7 +92,16 @@ const updateTool = async (req: Request, res: Response, next: NextFunction) => {
if (!workspaceId) {
throw new InternalFlowiseError(StatusCodes.NOT_FOUND, `Error: toolsController.updateTool - workspace ${workspaceId} not found!`)
}
const apiResponse = await toolsService.updateTool(req.params.id, req.body, workspaceId)
const body = req.body
// Explicit allowlist — id/workspaceId/timestamps must not be overrideable by client
const toolBody: Record<string, unknown> = {}
if (body.name !== undefined) toolBody.name = body.name
if (body.description !== undefined) toolBody.description = body.description
if (body.color !== undefined) toolBody.color = body.color
if (body.iconSrc !== undefined) toolBody.iconSrc = body.iconSrc
if (body.schema !== undefined) toolBody.schema = body.schema
if (body.func !== undefined) toolBody.func = body.func
const apiResponse = await toolsService.updateTool(req.params.id, toolBody, workspaceId)
return res.json(apiResponse)
} catch (error) {
next(error)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ export const destroyAllSessionsForUser = async (userId: string): Promise<void> =
await repository
.createQueryBuilder()
.delete()
.where(`JSON_EXTRACT(sess, '$.passport.user.id') = :userId`, { userId })
.where(`JSON_EXTRACT(data, '$.passport.user.id') = :userId`, { userId }) // express-mysql-session uses column name 'data' for session payload, not 'sess'
.execute()
break
case 'postgres':
Expand Down
4 changes: 2 additions & 2 deletions packages/server/src/services/credentials/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,15 +60,15 @@ const getAllCredentials = async (paramCredentialName: any, workspaceId: string)
...getWorkspaceSearchOptions(workspaceId)
}
const credentials = await appServer.AppDataSource.getRepository(Credential).findBy(searchOptions)
dbResponse.push(...credentials)
dbResponse.push(...credentials.map((c) => omit(c, ['encryptedData'])))
}
} else {
const searchOptions = {
credentialName: paramCredentialName,
...getWorkspaceSearchOptions(workspaceId)
}
const credentials = await appServer.AppDataSource.getRepository(Credential).findBy(searchOptions)
dbResponse = [...credentials]
dbResponse = credentials.map((c) => omit(c, ['encryptedData']))
}
// get shared credentials
if (workspaceId) {
Expand Down
1 change: 1 addition & 0 deletions packages/server/src/services/tools/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ const updateTool = async (toolId: string, toolBody: any, workspaceId: string): P
const updateTool = new Tool()
Object.assign(updateTool, toolBody)
appServer.AppDataSource.getRepository(Tool).merge(tool, updateTool)
tool.workspaceId = workspaceId // defense-in-depth: never trust client-supplied workspaceId
const dbResponse = await appServer.AppDataSource.getRepository(Tool).save(tool)
return dbResponse
} catch (error) {
Expand Down