-
Notifications
You must be signed in to change notification settings - Fork 1
SAST Severity Fixes #173
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
SAST Severity Fixes #173
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -18,14 +18,21 @@ const invalidRouteHandler = sharedMiddlewares.get('invalidRoute'); | |
| app.set('port', port); | ||
| app.set('logger', logger); | ||
| app.disable('x-powered-by'); | ||
| // app.use(helmet()); | ||
| app.use(helmet({ | ||
| hsts: { | ||
| maxAge: 31536000, // 1 year in seconds | ||
| includeSubDomains: true, | ||
| preload: true | ||
| } | ||
| })); | ||
|
Comment on lines
+22
to
+28
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: rg -n 'helmet' --type=ts -C3Repository: Sanketika-Obsrv/obsrv-web-console Length of output: 1078 🏁 Script executed: head -30 src/index.tsRepository: Sanketika-Obsrv/obsrv-web-console Length of output: 959 🏁 Script executed: head -30 src/app.tsRepository: Sanketika-Obsrv/obsrv-web-console Length of output: 1022 Duplicate Helmet registration —
🧰 Tools🪛 ESLint[error] 21-21: Insert (prettier/prettier) [error] 22-22: Insert (prettier/prettier) [error] 23-23: Insert (prettier/prettier) [error] 24-24: Insert (prettier/prettier) [error] 25-25: Replace (prettier/prettier) [error] 26-26: Replace (prettier/prettier) [error] 27-27: Replace (prettier/prettier) 🤖 Prompt for AI Agents |
||
| app.use(cors()); | ||
| app.use(express.static(path.join(__dirname, 'build'))); | ||
|
|
||
| // mount routers | ||
| mountRoutes(app); | ||
|
|
||
| app.get('*', function (req, res) { | ||
| res.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains; preload'); | ||
| res.sendFile(path.join(__dirname, 'build', 'index.html')); | ||
| }); | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
|
|
@@ -221,9 +221,11 @@ const generateDatasetState = async (state: Record<string, any>) => { | |||||||
| export default { | ||||||||
| name: 'dataset:state', | ||||||||
| handler: () => async (request: Request, response: Response, next: NextFunction) => { | ||||||||
| let { datasetId } = request.params; | ||||||||
| let { status } = request.query; | ||||||||
| let datasetId = _.get(request, 'params.datasetId'); | ||||||||
| let status = _.get(request, 'query.status'); | ||||||||
|
|
||||||||
| datasetId = status === "Live" ? _.split(datasetId, '.', 1)[0] : datasetId | ||||||||
|
Comment on lines
+226
to
227
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix lint errors: trailing whitespace and missing semicolon. ESLint reports a blank line with whitespace on Line 226 and a missing semicolon on Line 227. Also, double quotes should be single quotes per prettier config. Proposed fix const status = _.get(request, 'query.status');
-
- datasetId = status === "Live" ? _.split(datasetId, '.', 1)[0] : datasetId
+ datasetId = status === 'Live' ? _.split(datasetId, '.', 1)[0] : datasetId;📝 Committable suggestion
Suggested change
🧰 Tools🪛 ESLint[error] 226-226: Delete (prettier/prettier) [error] 227-227: Replace (prettier/prettier) 🤖 Prompt for AI Agents |
||||||||
| response.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains; preload'); | ||||||||
coderabbitai[bot] marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||
| try { | ||||||||
| const dataset = await fetchDataset({ datasetId, status }); | ||||||||
| const payload = { | ||||||||
|
|
||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,28 +1,27 @@ | ||||||||||||||||||
| import { NextFunction, Request, Response } from "express"; | ||||||||||||||||||
| import { fetchDataset, fetchDraftDataset } from "../services/dataset"; | ||||||||||||||||||
| import _ from "lodash"; | ||||||||||||||||||
| import { getDiff } from "json-difference"; | ||||||||||||||||||
| import { NextFunction, Request, Response } from 'express'; | ||||||||||||||||||
| import _ from 'lodash'; | ||||||||||||||||||
| import { fetchDataset, fetchDraftDataset } from '../services/dataset'; | ||||||||||||||||||
|
|
||||||||||||||||||
| export default { | ||||||||||||||||||
| name: 'dataset:exists', | ||||||||||||||||||
| handler: () => async (request: Request, response: Response, next: NextFunction) => { | ||||||||||||||||||
| const { datasetId } = request.params; | ||||||||||||||||||
| const datasetId = _.get(request.params, 'datasetId'); | ||||||||||||||||||
| response.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains; preload'); | ||||||||||||||||||
| try { | ||||||||||||||||||
| const liveDataset = await Promise.allSettled([fetchDataset({ datasetId })]) | ||||||||||||||||||
| if(liveDataset[0].status == 'fulfilled') { | ||||||||||||||||||
| const liveDataset = await Promise.allSettled([fetchDataset({ datasetId })]) | ||||||||||||||||||
| if (liveDataset[0].status === 'fulfilled') { | ||||||||||||||||||
| return response.status(200).json(liveDataset[0].value) | ||||||||||||||||||
| } | ||||||||||||||||||
| const draftDataset = await Promise.allSettled([fetchDraftDataset({ datasetId })]) | ||||||||||||||||||
| if(draftDataset[0].status == 'fulfilled') { | ||||||||||||||||||
|
|
||||||||||||||||||
| const draftDataset = await Promise.allSettled([fetchDraftDataset({ datasetId })]) | ||||||||||||||||||
| if (draftDataset[0].status === 'fulfilled') { | ||||||||||||||||||
| return response.status(200).json(draftDataset[0].value) | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| if(draftDataset[0].status == 'rejected') { | ||||||||||||||||||
| return response.status(_.get(draftDataset[0], ['reason', 'status'])).json(_.get(draftDataset[0], ['reason', 'response', 'data'])) | ||||||||||||||||||
| if (draftDataset[0].status === 'rejected') { | ||||||||||||||||||
| const errorData = _.get(draftDataset[0], ['reason', 'response', 'data']); | ||||||||||||||||||
| return response.status(_.get(draftDataset[0], ['reason', 'status'])).json(errorData) | ||||||||||||||||||
|
Comment on lines
+21
to
+23
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Bug: For Axios errors, the HTTP status code lives at Proposed fix if (draftDataset[0].status === 'rejected') {
const errorData = _.get(draftDataset[0], ['reason', 'response', 'data']);
- return response.status(_.get(draftDataset[0], ['reason', 'status'])).json(errorData)
+ const statusCode = _.get(draftDataset[0], ['reason', 'response', 'status'], 500);
+ return response.status(statusCode).json(errorData)
}📝 Committable suggestion
Suggested change
🧰 Tools🪛 ESLint[error] 23-23: Insert (prettier/prettier) 🤖 Prompt for AI Agents |
||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
|
|
||||||||||||||||||
| } catch (error) { | ||||||||||||||||||
| next(error); | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,20 +1,30 @@ | ||||||||||||||||||||||||||||||||||
| import { NextFunction, Request, Response } from "express"; | ||||||||||||||||||||||||||||||||||
| import { Kafka } from "kafkajs"; | ||||||||||||||||||||||||||||||||||
| import _ from "lodash"; | ||||||||||||||||||||||||||||||||||
| import * as _ from "lodash"; | ||||||||||||||||||||||||||||||||||
coderabbitai[bot] marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| export default { | ||||||||||||||||||||||||||||||||||
| name: 'connector:test', | ||||||||||||||||||||||||||||||||||
| handler: () => async (request: Request, response: Response, next: NextFunction) => { | ||||||||||||||||||||||||||||||||||
| response.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains; preload'); | ||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||
| const { kafkaBrokers, topic } = request.body; | ||||||||||||||||||||||||||||||||||
| const topic = _.get(request.body, 'topic', "").toString().trim(); | ||||||||||||||||||||||||||||||||||
| const kafkaBrokers = _.get(request.body, 'kafkaBrokers', "").toString().trim(); | ||||||||||||||||||||||||||||||||||
|
Comment on lines
+10
to
+11
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Use nullish coalescing or an explicit fallback: Proposed fix- const topic = _.get(request.body, 'topic', "").toString().trim();
- const kafkaBrokers = _.get(request.body, 'kafkaBrokers', "").toString().trim();
+ const topic = String(_.get(request.body, 'topic') ?? '').trim();
+ const kafkaBrokers = String(_.get(request.body, 'kafkaBrokers') ?? '').trim();📝 Committable suggestion
Suggested change
🧰 Tools🪛 ESLint[error] 10-10: Replace (prettier/prettier) [error] 11-11: Replace (prettier/prettier) 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| if (!kafkaBrokers || !topic) { | ||||||||||||||||||||||||||||||||||
| response.setHeader('Content-Type', 'application/json'); | ||||||||||||||||||||||||||||||||||
| return response.status(400).send({ error: "kafkaBrokers and topic are required" }); | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| const topicsList = await service.getTopics(kafkaBrokers); | ||||||||||||||||||||||||||||||||||
| const topicExists = topicsList.includes(topic); | ||||||||||||||||||||||||||||||||||
| if (!topicExists) throw { message: "Topic does not exist" }; | ||||||||||||||||||||||||||||||||||
| const result = { connectionEstablished: true, topicExists: topicExists } | ||||||||||||||||||||||||||||||||||
| if (!topicExists) throw new Error("Topic does not exist"); | ||||||||||||||||||||||||||||||||||
| const result = { connectionEstablished: true, topicExists: topicExists }; | ||||||||||||||||||||||||||||||||||
| response.setHeader('Content-Type', 'application/json'); | ||||||||||||||||||||||||||||||||||
| response.status(200).send(result); | ||||||||||||||||||||||||||||||||||
| } catch (error: any) { | ||||||||||||||||||||||||||||||||||
| console.log(error?.message); | ||||||||||||||||||||||||||||||||||
| next("Failed to establish connection to the client") | ||||||||||||||||||||||||||||||||||
| response.setHeader('Content-Type', 'application/json'); | ||||||||||||||||||||||||||||||||||
| response.status(500).send({ error: "Failed to establish connection to the client" }); | ||||||||||||||||||||||||||||||||||
|
Comment on lines
+20
to
+27
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Topic-not-found is misreported as a connection failure (500). Line 20 throws when the topic doesn't exist, but the catch block on line 27 returns a generic Consider returning the topic-not-found case as a successful connection with Proposed fix: return topicExists: false instead of throwing- if (!topicExists) throw new Error("Topic does not exist");
- const result = { connectionEstablished: true, topicExists: topicExists };
+ const result = { connectionEstablished: true, topicExists };📝 Committable suggestion
Suggested change
🧰 Tools🪛 ESLint[error] 20-20: Replace (prettier/prettier) [error] 25-25: Unexpected console statement. (no-console) [error] 27-27: Replace (prettier/prettier) 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,10 +1,24 @@ | ||
| import { IResponse } from '../types'; | ||
| import { v4 as uuidv4 } from 'uuid'; | ||
| import * as he from 'he'; | ||
|
|
||
| const transform = (payload: Partial<IResponse>) => { | ||
| const { id, ver = 'v1', ets = Date.now(), params = {}, responseCode = 'OK', result = {} } = payload; | ||
| let { id, ver = 'v1', ets = Date.now(), params = {}, responseCode = 'OK', result = {} } = payload; | ||
|
|
||
| const { resmsgid = `${uuidv4()}`, err = '', status = responseCode === 'OK' ? 'SUCCESSFUL' : 'FAILED', errmsg = '' } = params; | ||
| // Sanitize ID to prevent Reflected XSS | ||
| if (typeof id === 'string') { | ||
| id = he.encode(id); | ||
| } | ||
|
|
||
| let { resmsgid = `${uuidv4()}`, err = '', status = responseCode === 'OK' ? 'SUCCESSFUL' : 'FAILED', errmsg = '' } = params; | ||
|
|
||
| // Sanitize error messages to prevent Reflected XSS | ||
| if (typeof err === 'string') { | ||
| err = he.encode(err); | ||
| } | ||
| if (typeof errmsg === 'string') { | ||
| errmsg = he.encode(errmsg); | ||
| } | ||
|
Comment on lines
+6
to
+21
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. HTML-encoding JSON response values may cause double-encoding on the client side.
Consider whether the actual XSS vector is on the client side (DOM insertion via Also note that 🧰 Tools🪛 ESLint[error] 6-6: Insert (prettier/prettier) [error] 6-6: 'ver' is never reassigned. Use 'const' instead. (prefer-const) [error] 6-6: 'ets' is never reassigned. Use 'const' instead. (prefer-const) [error] 6-6: 'params' is never reassigned. Use 'const' instead. (prefer-const) [error] 6-6: 'responseCode' is never reassigned. Use 'const' instead. (prefer-const) [error] 6-6: 'result' is never reassigned. Use 'const' instead. (prefer-const) [error] 8-8: Insert (prettier/prettier) [error] 9-9: Insert (prettier/prettier) [error] 10-10: Replace (prettier/prettier) [error] 11-11: Insert (prettier/prettier) [error] 13-13: Insert (prettier/prettier) [error] 13-13: 'resmsgid' is never reassigned. Use 'const' instead. (prefer-const) [error] 13-13: 'status' is never reassigned. Use 'const' instead. (prefer-const) [error] 15-15: Replace (prettier/prettier) [error] 16-16: Insert (prettier/prettier) [error] 17-17: Replace (prettier/prettier) [error] 18-18: Replace (prettier/prettier) [error] 19-19: Insert (prettier/prettier) [error] 20-20: Insert (prettier/prettier) [error] 21-21: Insert (prettier/prettier) 🤖 Prompt for AI Agents |
||
|
|
||
| return { | ||
| id, | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.