Skip to content
This repository was archived by the owner on Aug 13, 2026. It is now read-only.

Commit a7b55ef

Browse files
Merge branch 'main' into igor/security-sunset
2 parents f3be00d + fe285d0 commit a7b55ef

11 files changed

Lines changed: 245 additions & 20 deletions

File tree

docker/Dockerfile

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@ RUN apk add --no-cache git python3 py3-pip make g++ build-base cairo-dev pango-d
1313
ENV PUPPETEER_SKIP_DOWNLOAD=true
1414

1515
# Install latest Flowise globally (specific version can be set: flowise@1.0.0)
16-
RUN npm install -g flowise
16+
# npm dedupe is required after install: npm's overrides resolver does not
17+
# consistently collapse every duplicate of an overridden package in one pass
18+
# on a tree this size/complexity
19+
RUN npm install -g flowise && npm --prefix "$(npm root -g)/flowise" dedupe
1720

1821
# Stage 2: Runtime stage
1922
FROM node:${NODE_VERSION}-alpine

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@
9999
"tmp": ">=0.2.4",
100100
"@elastic/transport": ">=8.9.3",
101101
"@modelcontextprotocol/sdk": ">=1.25.2",
102-
"multer": ">=2.1.1"
102+
"multer": "2.2.0"
103103
}
104104
},
105105
"engines": {

packages/agentflow/package.json

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,36 @@
6767
"react-dom": "^18.2.0",
6868
"reactflow": "^11.5.0"
6969
},
70+
"overrides": {
71+
"prebuild-install": "7.1.3",
72+
"axios": "1.15.0",
73+
"body-parser": "2.0.2",
74+
"braces": "3.0.3",
75+
"cross-spawn": "7.0.6",
76+
"form-data": "4.0.4",
77+
"glob-parent": "6.0.2",
78+
"http-proxy-middleware": "3.0.3",
79+
"json5": "2.2.3",
80+
"nth-check": "2.1.1",
81+
"path-to-regexp": "0.1.12",
82+
"prismjs": "1.29.0",
83+
"rollup": "4.45.0",
84+
"semver": "7.7.1",
85+
"set-value": "4.1.0",
86+
"solid-js": "1.9.11",
87+
"protobufjs": ">=7.5.5",
88+
"tar-fs": "3.1.1",
89+
"unset-value": "2.0.1",
90+
"webpack-dev-middleware": "7.4.2",
91+
"ws": "8.18.3",
92+
"xlsx": "0.18.5",
93+
"uuid": "^10.0.0",
94+
"@tootallnate/once": ">=3.0.1",
95+
"tmp": ">=0.2.4",
96+
"@elastic/transport": ">=8.9.3",
97+
"@modelcontextprotocol/sdk": ">=1.25.2",
98+
"multer": "2.2.0"
99+
},
70100
"dependencies": {
71101
"@codemirror/lang-javascript": "^6.2.0",
72102
"@codemirror/lang-json": "^6.0.0",

packages/components/package.json

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,35 @@
3030
"email": "henryheng@flowiseai.com"
3131
},
3232
"license": "SEE LICENSE IN LICENSE.md",
33+
"overrides": {
34+
"prebuild-install": "7.1.3",
35+
"axios": "1.15.0",
36+
"body-parser": "2.0.2",
37+
"braces": "3.0.3",
38+
"cross-spawn": "7.0.6",
39+
"form-data": "^4.0.4",
40+
"glob-parent": "6.0.2",
41+
"http-proxy-middleware": "3.0.3",
42+
"json5": "2.2.3",
43+
"nth-check": "2.1.1",
44+
"path-to-regexp": "0.1.12",
45+
"prismjs": "1.29.0",
46+
"rollup": "4.45.0",
47+
"semver": "7.7.1",
48+
"set-value": "4.1.0",
49+
"solid-js": "1.9.11",
50+
"protobufjs": ">=7.5.5",
51+
"tar-fs": "3.1.1",
52+
"unset-value": "2.0.1",
53+
"webpack-dev-middleware": "7.4.2",
54+
"ws": "^8.18.3",
55+
"xlsx": "0.18.5",
56+
"uuid": "^10.0.0",
57+
"@tootallnate/once": ">=3.0.1",
58+
"tmp": ">=0.2.4",
59+
"@elastic/transport": ">=8.9.3",
60+
"multer": "2.2.0"
61+
},
3362
"dependencies": {
3463
"@anthropic-ai/sdk": "^0.73.0",
3564
"@apidevtools/json-schema-ref-parser": "^11.7.0",
@@ -183,7 +212,7 @@
183212
"vm2": "3.11.2",
184213
"weaviate-client": "3.12.0",
185214
"winston": "^3.9.0",
186-
"ws": "^8.18.0",
215+
"ws": "^8.18.3",
187216
"xlsx": "0.18.5",
188217
"zod": "^3.25.76 || ^4",
189218
"zod-to-json-schema": "^3.24.6"

packages/observe/package.json

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,36 @@
6464
"react": "^18.2.0",
6565
"react-dom": "^18.2.0"
6666
},
67+
"overrides": {
68+
"prebuild-install": "7.1.3",
69+
"axios": "1.15.0",
70+
"body-parser": "2.0.2",
71+
"braces": "3.0.3",
72+
"cross-spawn": "7.0.6",
73+
"form-data": "4.0.4",
74+
"glob-parent": "6.0.2",
75+
"http-proxy-middleware": "3.0.3",
76+
"json5": "2.2.3",
77+
"nth-check": "2.1.1",
78+
"path-to-regexp": "0.1.12",
79+
"prismjs": "1.29.0",
80+
"rollup": "4.45.0",
81+
"semver": "7.7.1",
82+
"set-value": "4.1.0",
83+
"solid-js": "1.9.11",
84+
"protobufjs": ">=7.5.5",
85+
"tar-fs": "3.1.1",
86+
"unset-value": "2.0.1",
87+
"webpack-dev-middleware": "7.4.2",
88+
"ws": "8.18.3",
89+
"xlsx": "0.18.5",
90+
"uuid": "^10.0.0",
91+
"@tootallnate/once": ">=3.0.1",
92+
"tmp": ">=0.2.4",
93+
"@elastic/transport": ">=8.9.3",
94+
"@modelcontextprotocol/sdk": ">=1.25.2",
95+
"multer": "2.2.0"
96+
},
6797
"dependencies": {
6898
"@mui/x-tree-view": "^7.25.0",
6999
"@tabler/icons-react": "^3.7.0",

packages/server/package.json

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,35 @@
6161
"node": "^24"
6262
},
6363
"license": "SEE LICENSE IN LICENSE.md",
64+
"overrides": {
65+
"prebuild-install": "7.1.3",
66+
"axios": "1.15.0",
67+
"body-parser": "2.0.2",
68+
"braces": "3.0.3",
69+
"cross-spawn": "7.0.6",
70+
"form-data": "4.0.4",
71+
"glob-parent": "6.0.2",
72+
"http-proxy-middleware": "3.0.3",
73+
"json5": "2.2.3",
74+
"nth-check": "2.1.1",
75+
"path-to-regexp": "0.1.12",
76+
"prismjs": "1.29.0",
77+
"rollup": "4.45.0",
78+
"semver": "7.7.1",
79+
"set-value": "4.1.0",
80+
"solid-js": "1.9.11",
81+
"protobufjs": ">=7.5.5",
82+
"tar-fs": "3.1.1",
83+
"unset-value": "2.0.1",
84+
"webpack-dev-middleware": "7.4.2",
85+
"ws": "8.18.3",
86+
"xlsx": "0.18.5",
87+
"uuid": "^10.0.0",
88+
"@tootallnate/once": ">=3.0.1",
89+
"tmp": ">=0.2.4",
90+
"@elastic/transport": ">=8.9.3",
91+
"multer": "2.2.0"
92+
},
6493
"dependencies": {
6594
"@aws-sdk/client-secrets-manager": "^3.1014.0",
6695
"@bull-board/api": "^6.11.0",
@@ -121,7 +150,7 @@
121150
"lodash": "^4.17.21",
122151
"moment": "^2.29.3",
123152
"moment-timezone": "^0.5.34",
124-
"multer": "^2.1.1",
153+
"multer": "2.2.0",
125154
"multer-azure-blob-storage": "^1.2.0",
126155
"multer-cloud-storage": "^4.0.0",
127156
"multer-s3": "^3.0.1",

packages/server/src/enterprise/services/user.service.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ export const enum UserErrorMessage {
2626
USER_FOUND_MULTIPLE = 'User Found Multiple',
2727
INCORRECT_USER_EMAIL_OR_CREDENTIALS = 'Incorrect Email or Password',
2828
PASSWORDS_DO_NOT_MATCH = 'Passwords do not match',
29-
EMAIL_CHANGE_USE_CONFIRM_LINK = 'Use the confirm email change link from your email to complete this action.'
29+
EMAIL_CHANGE_USE_CONFIRM_LINK = 'Use the confirm email change link from your email to complete this action.',
30+
USER_INVITED_PENDING_ACTIVATION = 'You have a pending invitation. Please check your email and complete the invitation to activate your account before signing in.'
3031
}
3132
export class UserService {
3233
private telemetry: Telemetry
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import { describe, it, expect, jest, beforeEach } from '@jest/globals'
2+
import { QueryRunner } from 'typeorm'
3+
import { Platform } from '../../Interface'
4+
import { UserStatus } from '../database/entities/user.entity'
5+
import { UserErrorMessage } from '../services/user.service'
6+
7+
const mockReadUserByEmail = jest.fn() as jest.MockedFunction<(_email: string, _queryRunner: QueryRunner) => Promise<any>>
8+
const mockCreateQueryRunner = jest.fn() as jest.MockedFunction<() => any>
9+
const mockGetPlatformType = jest.fn() as jest.MockedFunction<() => Platform>
10+
11+
jest.mock('../../utils/getRunningExpressApp', () => ({
12+
getRunningExpressApp: jest.fn().mockImplementation(() => ({
13+
AppDataSource: { createQueryRunner: mockCreateQueryRunner },
14+
identityManager: { getPlatformType: mockGetPlatformType }
15+
}))
16+
}))
17+
18+
jest.mock('../services/user.service', () => ({
19+
UserService: jest.fn().mockImplementation(() => ({ readUserByEmail: mockReadUserByEmail }))
20+
}))
21+
22+
jest.mock('../services/organization.service', () => ({
23+
OrganizationService: jest.fn().mockImplementation(() => ({}))
24+
}))
25+
26+
jest.mock('../services/workspace-user.service', () => ({
27+
WorkspaceUserService: jest.fn().mockImplementation(() => ({}))
28+
}))
29+
30+
import SSOBase from './SSOBase'
31+
32+
class TestSSO extends SSOBase {
33+
getProviderName(): string {
34+
return 'Test SSO'
35+
}
36+
initialize(): void {}
37+
async refreshToken(): Promise<{ [key: string]: any }> {
38+
return {}
39+
}
40+
}
41+
42+
function makeQueryRunner() {
43+
return { connect: jest.fn(), release: jest.fn(), isReleased: false }
44+
}
45+
46+
describe('SSOBase.verifyAndLogin', () => {
47+
beforeEach(() => {
48+
jest.clearAllMocks()
49+
})
50+
51+
it('rejects an INVITED user instead of auto-activating them (invite-token bypass fix)', async () => {
52+
const queryRunner = makeQueryRunner()
53+
mockCreateQueryRunner.mockReturnValue(queryRunner)
54+
mockGetPlatformType.mockReturnValue(Platform.ENTERPRISE)
55+
mockReadUserByEmail.mockResolvedValue({
56+
id: 'user-1',
57+
email: 'invitee@example.com',
58+
status: UserStatus.INVITED,
59+
tempToken: 'secret-invite-token',
60+
tokenExpiry: new Date(Date.now() + 3600_000)
61+
})
62+
63+
const sso = new TestSSO({} as any)
64+
const done = jest.fn()
65+
66+
await sso.verifyAndLogin(
67+
{} as any,
68+
'invitee@example.com',
69+
done,
70+
{ displayName: 'Attacker' } as any,
71+
'access-token',
72+
'refresh-token'
73+
)
74+
75+
expect(mockReadUserByEmail).toHaveBeenCalledWith('invitee@example.com', queryRunner)
76+
expect(done).toHaveBeenCalledWith(
77+
{ name: 'SSO_LOGIN_FAILED', message: UserErrorMessage.USER_INVITED_PENDING_ACTIVATION },
78+
undefined
79+
)
80+
expect(queryRunner.release).toHaveBeenCalled()
81+
})
82+
})

packages/server/src/enterprise/sso/SSOBase.ts

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import { IAssignedWorkspace, LoggedInUser } from '../Interface.Enterprise'
55
import { getRunningExpressApp } from '../../utils/getRunningExpressApp'
66
import { UserErrorMessage, UserService } from '../services/user.service'
77
import { WorkspaceUserService } from '../services/workspace-user.service'
8-
import { AccountService } from '../services/account.service'
98
import { WorkspaceUser } from '../database/entities/workspace-user.entity'
109
import { OrganizationService } from '../services/organization.service'
1110
import { GeneralRole } from '../database/entities/role.entity'
@@ -67,18 +66,10 @@ abstract class SSOBase {
6766
if (user.status !== UserStatus.ACTIVE && getRunningExpressApp().identityManager.getPlatformType() === Platform.CLOUD)
6867
throw new InternalFlowiseError(StatusCodes.BAD_REQUEST, 'New registrations are currently closed.')
6968
if (user.status === UserStatus.INVITED) {
70-
const data: any = {
71-
user: {
72-
...user,
73-
email,
74-
name: profile.displayName || '',
75-
status: UserStatus.ACTIVE,
76-
credential: undefined
77-
}
78-
}
79-
const accountService = new AccountService()
80-
const newAccount = await accountService.register(data)
81-
user = newAccount.user
69+
// Do not auto-activate an invited user via SSO. Completing the invitation
70+
// proves control of the emailed tempToken; an SSO login only proves the
71+
// identity provider's email assertion, which is not equivalent proof.
72+
throw new InternalFlowiseError(StatusCodes.FORBIDDEN, UserErrorMessage.USER_INVITED_PENDING_ACTIVATION)
8273
}
8374
let wsUserOrUsers = await workspaceUserService.readWorkspaceUserByLastLogin(user?.id, queryRunner)
8475
wu = Array.isArray(wsUserOrUsers) && wsUserOrUsers.length > 0 ? wsUserOrUsers[0] : (wsUserOrUsers as WorkspaceUser)

packages/ui/package.json

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,36 @@
77
"name": "HenryHeng",
88
"email": "henryheng@flowiseai.com"
99
},
10+
"overrides": {
11+
"prebuild-install": "7.1.3",
12+
"axios": "1.15.0",
13+
"body-parser": "2.0.2",
14+
"braces": "3.0.3",
15+
"cross-spawn": "7.0.6",
16+
"form-data": "4.0.4",
17+
"glob-parent": "6.0.2",
18+
"http-proxy-middleware": "3.0.3",
19+
"json5": "2.2.3",
20+
"nth-check": "2.1.1",
21+
"path-to-regexp": "0.1.12",
22+
"prismjs": "1.29.0",
23+
"rollup": "4.45.0",
24+
"semver": "7.7.1",
25+
"set-value": "4.1.0",
26+
"solid-js": "1.9.11",
27+
"protobufjs": ">=7.5.5",
28+
"tar-fs": "3.1.1",
29+
"unset-value": "2.0.1",
30+
"webpack-dev-middleware": "7.4.2",
31+
"ws": "8.18.3",
32+
"xlsx": "0.18.5",
33+
"uuid": "^10.0.0",
34+
"@tootallnate/once": ">=3.0.1",
35+
"tmp": ">=0.2.4",
36+
"@elastic/transport": ">=8.9.3",
37+
"@modelcontextprotocol/sdk": ">=1.25.2",
38+
"multer": "2.2.0"
39+
},
1040
"dependencies": {
1141
"@codemirror/lang-javascript": "^6.2.1",
1242
"@codemirror/lang-json": "^6.0.1",

0 commit comments

Comments
 (0)