Skip to content

Commit 286121e

Browse files
authored
Bugfix/Auth URL Bypass (#3095)
add fixes to prevent bypassing api url
1 parent ace8b85 commit 286121e

File tree

1 file changed

+40
-20
lines changed

1 file changed

+40
-20
lines changed

packages/server/src/index.ts

Lines changed: 40 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,8 @@ export class App {
135135
'/api/v1/ip',
136136
'/api/v1/ping'
137137
]
138+
const URL_CASE_INSENSITIVE_REGEX: RegExp = /\/api\/v1\//i
139+
const URL_CASE_SENSITIVE_REGEX: RegExp = /\/api\/v1\//
138140

139141
if (process.env.FLOWISE_USERNAME && process.env.FLOWISE_PASSWORD) {
140142
const username = process.env.FLOWISE_USERNAME
@@ -143,37 +145,55 @@ export class App {
143145
users: { [username]: password }
144146
})
145147
this.app.use(async (req, res, next) => {
146-
if (/\/api\/v1\//i.test(req.url)) {
147-
if (whitelistURLs.some((url) => new RegExp(url, 'i').test(req.url))) {
148-
next()
149-
} else if (req.headers['x-request-from'] === 'internal') {
150-
basicAuthMiddleware(req, res, next)
151-
} else {
152-
const isKeyValidated = await validateAPIKey(req)
153-
if (!isKeyValidated) {
154-
return res.status(401).json({ error: 'Unauthorized Access' })
148+
// Step 1: Check if the req path contains /api/v1 regardless of case
149+
if (URL_CASE_INSENSITIVE_REGEX.test(req.path)) {
150+
// Step 2: Check if the req path is case sensitive
151+
if (URL_CASE_SENSITIVE_REGEX.test(req.path)) {
152+
// Step 3: Check if the req path is in the whitelist
153+
const isWhitelisted = whitelistURLs.some((url) => req.path.startsWith(url))
154+
if (isWhitelisted) {
155+
next()
156+
} else if (req.headers['x-request-from'] === 'internal') {
157+
basicAuthMiddleware(req, res, next)
158+
} else {
159+
const isKeyValidated = await validateAPIKey(req)
160+
if (!isKeyValidated) {
161+
return res.status(401).json({ error: 'Unauthorized Access' })
162+
}
163+
next()
155164
}
156-
next()
165+
} else {
166+
return res.status(401).json({ error: 'Unauthorized Access' })
157167
}
158168
} else {
169+
// If the req path does not contain /api/v1, then allow the request to pass through, example: /assets, /canvas
159170
next()
160171
}
161172
})
162173
} else {
163174
this.app.use(async (req, res, next) => {
164-
if (/\/api\/v1\//i.test(req.url)) {
165-
if (whitelistURLs.some((url) => new RegExp(url, 'i').test(req.url))) {
166-
next()
167-
} else if (req.headers['x-request-from'] === 'internal') {
168-
next()
169-
} else {
170-
const isKeyValidated = await validateAPIKey(req)
171-
if (!isKeyValidated) {
172-
return res.status(401).json({ error: 'Unauthorized Access' })
175+
// Step 1: Check if the req path contains /api/v1 regardless of case
176+
if (URL_CASE_INSENSITIVE_REGEX.test(req.path)) {
177+
// Step 2: Check if the req path is case sensitive
178+
if (URL_CASE_SENSITIVE_REGEX.test(req.path)) {
179+
// Step 3: Check if the req path is in the whitelist
180+
const isWhitelisted = whitelistURLs.some((url) => req.path.startsWith(url))
181+
if (isWhitelisted) {
182+
next()
183+
} else if (req.headers['x-request-from'] === 'internal') {
184+
next()
185+
} else {
186+
const isKeyValidated = await validateAPIKey(req)
187+
if (!isKeyValidated) {
188+
return res.status(401).json({ error: 'Unauthorized Access' })
189+
}
190+
next()
173191
}
174-
next()
192+
} else {
193+
return res.status(401).json({ error: 'Unauthorized Access' })
175194
}
176195
} else {
196+
// If the req path does not contain /api/v1, then allow the request to pass through, example: /assets, /canvas
177197
next()
178198
}
179199
})

0 commit comments

Comments
 (0)