From 449548f965a127855e5e46053df6d40a9de0f43a Mon Sep 17 00:00:00 2001 From: petruki <31597636+petruki@users.noreply.github.com> Date: Thu, 8 Jan 2026 07:46:43 -0800 Subject: [PATCH] patch: prevent nosql injection for metric resources --- src/routers/metric.js | 23 +++++++++++++++-------- src/services/metric.js | 19 +++++++++++-------- 2 files changed, 26 insertions(+), 16 deletions(-) diff --git a/src/routers/metric.js b/src/routers/metric.js index a505565..3e00bcc 100644 --- a/src/routers/metric.js +++ b/src/routers/metric.js @@ -15,12 +15,19 @@ const router = new express.Router(); // GET /metric/data/ID?sortBy=-date;key;component;result // GET /metric/data/ID?page=1 router.get('/metric/data/', auth, [ - check('domainid').isMongoId(), - check('page', 'page is required as query parameter').isLength({ min: 1 }) + query('domainid').isMongoId(), + query('page', 'page is required as query parameter').isLength({ min: 1 }), + query('result').optional().isBoolean(), + query('key').optional().isLength({ max: 30 }).isString(), + query('environment').optional().isLength({ max: 30 }).isString(), + query('component').optional().isLength({ max: 50 }).isString(), + query('group').optional().isLength({ max: 30 }).isString(), + query('dateBefore').optional().isISO8601(), + query('dateAfter').optional().isISO8601() ], validate, async (req, res) => { try { - const page = String(req.query.page); - if (isNaN(page)) { + const page = Number(req.query.page); + if (Number.isNaN(page)) { throw new TypeError('Page value should be a number'); } @@ -39,11 +46,11 @@ router.get('/metric/statistics/', auth, [ query('domainid').isMongoId(), query('statistics', 'add one or more options {swicthers,components,reasons,all} separed by comma').isLength({ min: 3 }), query('dateGroupPattern', 'e.g. YYYY-MM-DD HH:mm').optional().isLength({ max: 16 }), - query('key').optional().isLength({ max: 30 }), - query('environment').optional().isLength({ max: 30 }), + query('key').optional().isLength({ max: 30 }).isString(), + query('environment').optional().isLength({ max: 30 }).isString(), query('result').optional().isBoolean(), - query('component').optional().isLength({ max: 50 }), - query('group').optional().isLength({ max: 30 }), + query('component').optional().isLength({ max: 50 }).isString(), + query('group').optional().isLength({ max: 30 }).isString(), query('dateBefore').optional().isISO8601(), query('dateAfter').optional().isISO8601() ], validate, async (req, res) => { diff --git a/src/services/metric.js b/src/services/metric.js index 57d1a89..9a0522c 100644 --- a/src/services/metric.js +++ b/src/services/metric.js @@ -1,6 +1,6 @@ import moment from 'moment'; import { NotFoundError } from '../exceptions/index.js'; -import { verifyOwnership } from '../helpers/index.js'; +import { verifyOwnership, formatInput } from '../helpers/index.js'; import { EnvType } from '../models/environment.js'; import { Metric } from '../models/metric.js'; import { ActionTypes, RouterTypes } from '../models/permission.js'; @@ -182,26 +182,29 @@ function buildMetricsFilter(req) { aggregate.match({ $expr: { $eq: [{ $toString: '$domain' }, args.domain] } }); if (req.query.environment) { - args.environment = req.query.environment; - aggregate.match({ environment: String(req.query.environment) }); + const environment = formatInput(String(req.query.environment)); + args.environment = environment; + aggregate.match({ environment: environment }); } else { args.environment = EnvType.DEFAULT; aggregate.match({ environment: EnvType.DEFAULT }); } if (req.query.result) { - args.result = req.query.result; + args.result = Boolean(req.query.result); aggregate.match({ result: String(req.query.result) === 'true' }); } if (req.query.component) { - args.component = req.query.component; - aggregate.match({ component: String(req.query.component) }); + const component = formatInput(String(req.query.component)); + args.component = component; + aggregate.match({ component: component }); } if (req.query.group) { - args.group = req.query.group; - aggregate.match({ group: String(req.query.group) }); + const group = formatInput(String(req.query.group), { allowSpace: true }); + args.group = group; + aggregate.match({ group: group }); } if (req.query.dateBefore && !req.query.dateAfter) {