@contrast/assess
Advanced tools
Comparing version 1.8.0 to 1.9.0
@@ -18,4 +18,3 @@ /* | ||
const { InputType, signatures } = require('@contrast/common'); | ||
const { InputType, match } = require('@contrast/common'); | ||
const annotationRegExp = /^(A|O|R|P|P\d+)$/; | ||
@@ -52,3 +51,3 @@ | ||
if (!name) { | ||
logger.debug({ name }, baseMessage, 'invalid name'); | ||
logger.debug({ data }, baseMessage, 'invalid name'); | ||
return null; | ||
@@ -82,2 +81,4 @@ } | ||
name = '', | ||
moduleName, | ||
methodName, | ||
history = [], | ||
@@ -108,6 +109,4 @@ object = { value: null, tracked: false }, | ||
const signature = signatures.get(name); | ||
if (!signature) { | ||
logger.debug({ name }, 'Propagation event not created: no signature found for this name'); | ||
if (!name) { | ||
logger.debug({ name }, 'Propagation event not created: invalid name'); | ||
return null; | ||
@@ -122,4 +121,4 @@ } | ||
if ( | ||
((source && !source.match(annotationRegExp)) || (!source && !signature.source)) || | ||
((target && !target.match(annotationRegExp)) || (!target && !signature.target)) | ||
(!source || !match(source, annotationRegExp)) || | ||
(!target || !match(target, annotationRegExp)) | ||
) { | ||
@@ -143,2 +142,4 @@ logger.debug({ name, source, target }, 'Propagation event not created: %s', 'invalid source/target'); | ||
name, | ||
moduleName, | ||
methodName, | ||
object, | ||
@@ -164,2 +165,4 @@ removedTags, | ||
name = '', | ||
moduleName, | ||
methodName, | ||
history = [], | ||
@@ -179,5 +182,4 @@ object = { value: null, tracked: false }, | ||
} | ||
const signature = signatures.get(name); | ||
if (!signature) { | ||
logger.debug({ name }, 'no signature found for sink event name'); | ||
if (!name) { | ||
logger.debug({ data }, 'no sink event name'); | ||
return null; | ||
@@ -190,3 +192,3 @@ } | ||
if ( | ||
((source && !source.match(annotationRegExp)) || (!source && !signature.source)) | ||
(!source || !source.match(annotationRegExp)) | ||
) { | ||
@@ -209,2 +211,4 @@ logger.debug({ data }, 'malformed or missing sink event source field'); | ||
name, | ||
moduleName, | ||
methodName, | ||
object, | ||
@@ -211,0 +215,0 @@ result, |
@@ -25,2 +25,3 @@ /* | ||
require('./install/ejs')(core); | ||
require('./install/mongoose')(core); | ||
require('./install/pug')(core); | ||
@@ -37,3 +38,5 @@ require('./install/string')(core); | ||
require('./install/handlebars-utils-escape-expression')(core); | ||
require('./install/isnumeric-0')(core); | ||
require('./install/mysql-connection-escape')(core); | ||
require('./install/parse-int')(core); | ||
require('./install/pug-runtime-escape')(core); | ||
@@ -40,0 +43,0 @@ require('./install/sql-template-strings')(core); |
@@ -22,3 +22,3 @@ /* | ||
const { patchType } = require('../common'); | ||
const { isString } = require('@contrast/common'); | ||
const { isString, join, inspect } = require('@contrast/common'); | ||
@@ -67,12 +67,13 @@ module.exports = function(core) { | ||
install() { | ||
const originalJoin = Array.prototype.join; | ||
const name = 'Array.prototype.join'; | ||
patcher.patch(Array.prototype, 'join', { | ||
name: 'Array.prototype.join', | ||
name, | ||
patchType, | ||
post(data) { | ||
const { args, obj, result, hooked, orig } = data; | ||
const { args: origArgs, obj, result, hooked, orig } = data; | ||
if (!result || !sources.getStore()?.assess || instrumentation.isLocked()) return; | ||
const resultInfo = tracker.getData(result); | ||
const delimiter = args[0] === undefined ? ',' : args[0]; | ||
const delimiter = origArgs[0] === undefined ? ',' : origArgs[0]; | ||
const delimiterLength = delimiter.length; | ||
@@ -82,10 +83,19 @@ const delimiterInfo = tracker.getData(delimiter); | ||
const { newTags, newHistory: history } = accumulateTags(obj, {}, 0, initHistory, delimiterLength, delimiterInfo?.tags); | ||
const object = { | ||
value: obj && join(obj), | ||
tracked: false | ||
}; | ||
const args = [{ | ||
value: delimiterInfo ? delimiterInfo.value : delimiter, | ||
tracked: !!delimiterInfo | ||
}]; | ||
if (history.size) { | ||
const event = createPropagationEvent({ | ||
name: 'Array.prototype.join', | ||
object: { | ||
value: originalJoin.call(obj), | ||
tracked: false | ||
}, | ||
name, | ||
moduleName: 'Array', | ||
methodName: 'prototype.join', | ||
context: `${object.value}.join('${inspect(args[0].value) || ''})`, | ||
object, | ||
result: { | ||
@@ -95,6 +105,3 @@ value: resultInfo ? resultInfo.value : result, | ||
}, | ||
args: [{ | ||
value: delimiterInfo ? delimiterInfo.value : delimiter, | ||
tracked: !!delimiterInfo | ||
}], | ||
args, | ||
tags: newTags, | ||
@@ -101,0 +108,0 @@ history: Array.from(history), |
@@ -49,2 +49,4 @@ /* | ||
args: data.args.map((a) => ({ tracked: false, value: a })), | ||
moduleName: 'Buffer', | ||
methodName: 'prototype.toString', | ||
context: 'buffer.toString()', | ||
@@ -51,0 +53,0 @@ object: { tracked: true, value: 'Buffer' }, |
@@ -81,2 +81,4 @@ /* | ||
context: `${inspect(leftArg)} + ${inspect(rightArg)}`, | ||
moduleName: 'global', | ||
methodName: 'ContrastMethods.add', | ||
history, | ||
@@ -83,0 +85,0 @@ object: { |
@@ -31,2 +31,3 @@ /* | ||
require('./add')(core); | ||
require('./number')(core); | ||
require('./tag')(core); | ||
@@ -33,0 +34,0 @@ require('./string')(core); |
@@ -18,4 +18,14 @@ /* | ||
const { DataflowTag } = require('@contrast/common'); | ||
const { patchType } = require('../../common'); | ||
function metadataUpdate(strInfo, event) { | ||
for (const key of Object.keys(strInfo)) { | ||
if (key === 'value' || key === 'extern') continue; | ||
delete strInfo[key]; | ||
} | ||
Object.assign(strInfo, event); | ||
} | ||
module.exports = function(core) { | ||
@@ -27,3 +37,4 @@ const { | ||
dataflow: { | ||
tracker | ||
tracker, | ||
eventFactory: { createPropagationEvent }, | ||
}, | ||
@@ -35,4 +46,5 @@ } | ||
install() { | ||
const name = 'ContrastMethods.String'; | ||
patcher.patch(global.ContrastMethods, 'String', { | ||
name: 'ContrastMethods.String', | ||
name, | ||
patchType, | ||
@@ -44,3 +56,3 @@ post(data) { | ||
let argInfo = tracker.getData(arg); | ||
if (tracker.getData(data.result)) return; | ||
const objInfo = tracker.getData(data.obj); | ||
@@ -55,7 +67,42 @@ if (data.obj && !argInfo) { | ||
const { extern } = tracker.track(data.result, argInfo); | ||
const history = [{ ...argInfo }]; | ||
const strLength = typeof arg === 'string' ? arg.length : arg.toString().length; | ||
const event = createPropagationEvent({ | ||
addedTags: [DataflowTag.STRING_TYPE_CHECKED], | ||
name, | ||
moduleName: 'global', | ||
methodName: 'ContrastMethods.String', | ||
context: `${name}('${argInfo.value}')`, | ||
history, | ||
object: { | ||
tracked: !!objInfo, | ||
value: objInfo ? objInfo.value : data.obj, | ||
}, | ||
args: [{ tracked: true, value: argInfo.value }], | ||
source: 'P', | ||
tags: { | ||
...argInfo.tags, | ||
[DataflowTag.STRING_TYPE_CHECKED]: [0, strLength - 1], | ||
}, | ||
target: 'R', | ||
stacktraceOpts: { | ||
prependFrames: [data.orig], | ||
}, | ||
result: { | ||
value: data.result, | ||
tracked: true | ||
}, | ||
}); | ||
if (extern) { | ||
data.result = extern; | ||
if (!event) { | ||
return; | ||
} | ||
const resultInfo = tracker.getData(data.result); | ||
if (resultInfo) { | ||
metadataUpdate(resultInfo, event); | ||
} else { | ||
metadataUpdate(argInfo, event); | ||
} | ||
} | ||
@@ -62,0 +109,0 @@ }); |
@@ -20,3 +20,3 @@ /* | ||
module.exports = function (core) { | ||
module.exports = function(core) { | ||
const { | ||
@@ -83,2 +83,4 @@ assess: { | ||
context: `\`${context}\``, | ||
moduleName: 'global', | ||
methodName: 'ContrastMethods.tag', | ||
history: Array.from(history), | ||
@@ -85,0 +87,0 @@ object: { |
@@ -37,4 +37,6 @@ /* | ||
install() { | ||
const name = 'global.decodeURIComponent'; | ||
patcher.patch(global, 'decodeURIComponent', { | ||
name: 'global.decodeURIComponent', | ||
name, | ||
patchType, | ||
@@ -59,3 +61,6 @@ post(data) { | ||
const event = createPropagationEvent({ | ||
name: 'global.decodeURIComponent', | ||
name, | ||
moduleName: 'global', | ||
methodName: 'decodeURIComponent', | ||
context: `decodeURIComponent('${argInfo.value}')`, | ||
object: { | ||
@@ -72,2 +77,4 @@ value: createObjectLabel('global'), | ||
history, | ||
source: 'P', | ||
target: 'R', | ||
removedTags: [URL_ENCODED], | ||
@@ -74,0 +81,0 @@ stacktraceOpts: { |
@@ -39,4 +39,5 @@ /* | ||
depHooks.resolve({ name: 'ejs', file: 'lib/utils.js', version: '>=2.6.2' }, (ejsUtils, version) => { | ||
const name = 'ejs.utils.escapeXML'; | ||
patcher.patch(ejsUtils, 'escapeXML', { | ||
name: 'ejs.utils.escapeXML', | ||
name, | ||
patchType, | ||
@@ -58,3 +59,6 @@ post(data) { | ||
const event = createPropagationEvent({ | ||
name: 'ejs.utils.escapeXML', | ||
name, | ||
context: `ejs.utils.escapeXML('${argInfo.value}')`, | ||
moduleName: 'ejs', | ||
methodName: 'escapeXML', | ||
object: { | ||
@@ -76,2 +80,4 @@ value: `[${createModuleLabel('ejs', version)}].utils`, | ||
}, | ||
source: 'P', | ||
target: 'R', | ||
}); | ||
@@ -78,0 +84,0 @@ |
@@ -37,4 +37,6 @@ /* | ||
install() { | ||
const name = 'global.encodeURIComponent'; | ||
patcher.patch(global, 'encodeURIComponent', { | ||
name: 'global.encodeURIComponent', | ||
name, | ||
patchType, | ||
@@ -58,3 +60,6 @@ post(data) { | ||
const event = createPropagationEvent({ | ||
name: 'global.encodeURIComponent', | ||
name, | ||
moduleName: 'global', | ||
methodName: 'encodeURIComponent', | ||
context: `encodeURIComponent('${argInfo.value}')`, | ||
object: { | ||
@@ -71,2 +76,4 @@ value: createObjectLabel('global'), | ||
history, | ||
source: 'P', | ||
target: 'R', | ||
addedTags: [URL_ENCODED], | ||
@@ -73,0 +80,0 @@ stacktraceOpts: { |
@@ -38,5 +38,7 @@ /* | ||
install() { | ||
depHooks.resolve({ name: 'escape-html' }, (escapeHtml, version) => | ||
patcher.patch(escapeHtml, { | ||
name: 'escape-html', | ||
depHooks.resolve({ name: 'escape-html' }, (escapeHtml) => { | ||
const name = 'escape-html'; | ||
return patcher.patch(escapeHtml, { | ||
name, | ||
patchType, | ||
@@ -58,3 +60,6 @@ post(data) { | ||
const event = createPropagationEvent({ | ||
name: 'escape-html', | ||
name, | ||
moduleName: 'escape-html', | ||
methodName: '', | ||
context: `escapeHtml(${argInfo.value})`, | ||
object: { | ||
@@ -71,2 +76,4 @@ value: 'escape-html', | ||
history, | ||
source: 'P', | ||
target: 'R', | ||
addedTags: [HTML_ENCODED], | ||
@@ -91,3 +98,4 @@ stacktraceOpts: { | ||
} | ||
}) | ||
}); | ||
} | ||
); | ||
@@ -94,0 +102,0 @@ }, |
@@ -37,4 +37,6 @@ /* | ||
install() { | ||
const name = 'global.escape'; | ||
patcher.patch(global, 'escape', { | ||
name: 'global.escape', | ||
name, | ||
patchType, | ||
@@ -56,3 +58,6 @@ post(data) { | ||
const event = createPropagationEvent({ | ||
name: 'global.escape', | ||
name, | ||
moduleName: 'global', | ||
methodName: 'escape', | ||
context: `escape('${argInfo.value}')`, | ||
object: { | ||
@@ -69,2 +74,4 @@ value: createObjectLabel('global'), | ||
history, | ||
source: 'P', | ||
target: 'R', | ||
addedTags: [WEAK_URL_ENCODED], | ||
@@ -71,0 +78,0 @@ stacktraceOpts: { |
@@ -24,3 +24,3 @@ /* | ||
} = require('../../tag-utils'); | ||
const { patchType, createModuleLabel } = require('../common'); | ||
const { patchType } = require('../common'); | ||
@@ -40,4 +40,6 @@ module.exports = function(core) { | ||
depHooks.resolve({ name: 'handlebars', version: '>=4.0.0' }, (handlebars, version) => { | ||
const name = 'handlebars.Utils.escapeExpression'; | ||
patcher.patch(handlebars.Utils, 'escapeExpression', { | ||
name: 'handlebars.Utils.escapeExpression', | ||
name, | ||
patchType, | ||
@@ -59,5 +61,8 @@ post(data) { | ||
const event = createPropagationEvent({ | ||
name: 'handlebars.Utils.escapeExpression', | ||
name, | ||
moduleName: 'handlebars', | ||
methodName: 'Utils.escapeExpression', | ||
context: `${name}('${argInfo.value}')`, | ||
object: { | ||
value: `[${createModuleLabel('handlebars', version)}].Utils`, | ||
value: 'handlebars.Utils', | ||
tracked: false | ||
@@ -73,2 +78,4 @@ }, | ||
history, | ||
source: 'P', | ||
target: 'R', | ||
stacktraceOpts: { | ||
@@ -75,0 +82,0 @@ constructorOpt: hooked, |
@@ -31,4 +31,5 @@ /* | ||
require('./stringify')(core); | ||
require('./parse')(core); | ||
return jsonInstrumentation; | ||
}; |
@@ -84,4 +84,4 @@ /* | ||
function getUntrustedSpaceProps(space) { | ||
// it can't be a problem if it's not a string, if the string is all spaces, or | ||
// if the string is zero length. | ||
// it can't be a problem if it's not a string, if the string is all spaces, or | ||
// if the string is zero length. | ||
if (!isString(space) || match(space, /^\s+$/) || !space) { | ||
@@ -243,4 +243,6 @@ return null; | ||
const event = createPropagationEvent({ | ||
context: method, | ||
context: `${method}(${ret})`, | ||
name: method, | ||
moduleName: 'JSON', | ||
methodName: 'stringify', | ||
history: Array.from(metadata.history), | ||
@@ -247,0 +249,0 @@ object: { |
@@ -53,2 +53,5 @@ /* | ||
name: eventName, | ||
moduleName: 'mysql', | ||
methodName: 'escape', | ||
context: `mysql.escape('${argInfo.value}')`, | ||
object: { | ||
@@ -66,2 +69,4 @@ value: objectValue, | ||
history, | ||
source: 'P', | ||
target: 'R', | ||
stacktraceOpts: { | ||
@@ -68,0 +73,0 @@ constructorOpt: hooked, |
@@ -39,4 +39,6 @@ /* | ||
depHooks.resolve({ name: 'pug-runtime' }, (pugRuntime, version) => { | ||
const name = 'pug-runtime.escape'; | ||
patcher.patch(pugRuntime, 'escape', { | ||
name: 'pug-runtime.escape', | ||
name, | ||
patchType, | ||
@@ -58,3 +60,6 @@ post(data) { | ||
const event = createPropagationEvent({ | ||
name: 'pug-runtime.escape', | ||
name, | ||
moduleName: 'pug-runtime', | ||
methodName: 'escape', | ||
context: `pugRuntime.escape('${argInfo.value}')`, | ||
object: { | ||
@@ -72,2 +77,4 @@ value: createModuleLabel('pug-runtime', version), | ||
history, | ||
source: 'P', | ||
target: 'R', | ||
stacktraceOpts: { | ||
@@ -74,0 +81,0 @@ constructorOpt: hooked, |
@@ -18,6 +18,7 @@ /* | ||
const util = require('util'); | ||
const querystring = require('querystring'); | ||
const { | ||
DataflowTag: { URL_ENCODED } | ||
DataflowTag: { URL_ENCODED }, | ||
inspect, | ||
join | ||
} = require('@contrast/common'); | ||
@@ -50,4 +51,8 @@ | ||
const resultInfo = tracker.getData(result); | ||
const [, ...restOfArgsValues] = data.origArgs.map(inspect); | ||
const event = createPropagationEvent({ | ||
name: data.name, | ||
context: `querystring.parse('${trackingData.value}', ${join(restOfArgsValues, ', ')})`, | ||
moduleName: 'querystring', | ||
methodName: 'parse', | ||
history: [trackingData], | ||
@@ -58,9 +63,6 @@ object: { | ||
}, | ||
args: data.origArgs.map((arg) => { | ||
const argInfo = tracker.getData(arg); | ||
return { | ||
value: argInfo ? argInfo.value : util.inspect(arg), | ||
tracked: !!argInfo | ||
}; | ||
}), | ||
args: data.origArgs.map((_arg, idx) => ({ | ||
value: idx === 0 ? trackingData.value : restOfArgsValues[idx - 1], | ||
tracked: !!idx === 0 | ||
})), | ||
result: { | ||
@@ -67,0 +69,0 @@ value: result, |
@@ -24,3 +24,3 @@ /* | ||
module.exports = function (core) { | ||
module.exports = function(core) { | ||
const { | ||
@@ -62,5 +62,6 @@ scopes: { sources, instrumentation }, | ||
const origEscape = sqlString.escape; | ||
const name = 'sequelize.escape'; | ||
patcher.patch(sqlString, 'escape', { | ||
name: 'sequelize.escape', | ||
name, | ||
patchType, | ||
@@ -90,4 +91,6 @@ post(data) { | ||
const event = createPropagationEvent({ | ||
context: 'sequelize.escape', | ||
context: `sequelize.escape('${argInfo.value}')`, | ||
name: 'sequelize/lib/sql-string.escape', | ||
moduleName: 'sequelize', | ||
methodName: 'escape', | ||
object: { | ||
@@ -94,0 +97,0 @@ value: createModuleLabel('sequelize/lib/sql-string.escape', version), |
@@ -36,4 +36,6 @@ /* | ||
depHooks.resolve({ name: 'sql-template-strings' }, (sqlTemplateStrings, version) => { | ||
const name = 'sql-template-strings.SQL'; | ||
patcher.patch(sqlTemplateStrings, 'SQL', { | ||
name: 'sql-template-strings.SQL', | ||
name, | ||
patchType, | ||
@@ -59,3 +61,6 @@ post(data) { | ||
const event = createPropagationEvent({ | ||
name: 'sql-template-strings.SQL', | ||
name, | ||
moduleName: 'sql-template-strings', | ||
methodName: 'SQL', | ||
context: `SQL\`${argInfo.value}\``, | ||
object: { | ||
@@ -73,2 +78,4 @@ value: createModuleLabel('sql-template-strings', version), | ||
history, | ||
source: 'P', | ||
target: 'R', | ||
stacktraceOpts: { | ||
@@ -75,0 +82,0 @@ constructorOpt: hooked, |
@@ -21,2 +21,3 @@ /* | ||
} = require('../../../tag-utils'); | ||
const { join, inspect } = require('@contrast/common'); | ||
const { patchType } = require('../../common'); | ||
@@ -35,4 +36,6 @@ | ||
install() { | ||
const name = 'String.prototype.concat'; | ||
patcher.patch(String.prototype, 'concat', { | ||
name: 'String.prototype.concat', | ||
name, | ||
patchType, | ||
@@ -75,3 +78,6 @@ post(data) { | ||
const event = createPropagationEvent({ | ||
name: 'String.prototype.concat', | ||
name, | ||
moduleName: 'String', | ||
methodName: 'prototype.concat', | ||
context: `${inspect(objInfo?.value) || String(obj)}.concat(${join(argsData.map(d => d.value), ', ')})`, | ||
object: { | ||
@@ -78,0 +84,0 @@ value: objInfo?.value || String(obj), |
@@ -32,4 +32,6 @@ /* | ||
['toLowerCase', 'toUpperCase', 'toLocaleLowerCase', 'toLocaleUpperCase'].forEach((method) => { | ||
const name = `String.prototype.${method}`; | ||
patcher.patch(String.prototype, method, { | ||
name: `String.prototype.${method}`, | ||
name, | ||
patchType, | ||
@@ -47,3 +49,6 @@ post(data) { | ||
const event = createPropagationEvent({ | ||
name: `String.prototype.${method}`, | ||
name, | ||
moduleName: 'String', | ||
methodName: `prototype.${method}`, | ||
context: `'${objInfo.value}'.${method}()`, | ||
object: { | ||
@@ -50,0 +55,0 @@ value: objInfo.value, |
@@ -21,2 +21,3 @@ /* | ||
} = require('../../../tag-utils'); | ||
const { inspect } = require('@contrast/common'); | ||
const { patchType } = require('../../common'); | ||
@@ -61,4 +62,5 @@ const htmlTagsLengths = { | ||
install() { | ||
const name = 'String.prototype.anchor'; | ||
patcher.patch(String.prototype, 'anchor', { | ||
name: 'String.prototype.anchor', | ||
name, | ||
patchType, | ||
@@ -80,3 +82,6 @@ post(data) { | ||
const event = createPropagationEvent({ | ||
name: 'String.prototype.anchor', | ||
name, | ||
moduleName: 'String', | ||
methodName: 'prototype.anchor', | ||
context: `${inspect(objInfo?.value) || String(obj)}.anchor(${argInfo ? argInfo.value : arg})`, | ||
object: { | ||
@@ -91,3 +96,3 @@ value: objInfo?.value || String(obj), | ||
args: [ | ||
{ value: arg, tracked: !!argInfo } | ||
{ value: argInfo ? argInfo.value : arg, tracked: !!argInfo } | ||
], | ||
@@ -116,4 +121,6 @@ tags: adjustTags('anchor', objInfo?.tags, `${arg}`.length, argInfo?.tags), | ||
['big', 'blink', 'italics', 'small', 'strike', 'sub', 'fixed'].forEach((method) => { | ||
const name = `String.prototype.${method}`; | ||
patcher.patch(String.prototype, method, { | ||
name: `String.prototype.${method}`, | ||
name, | ||
patchType, | ||
@@ -131,3 +138,6 @@ post(data) { | ||
const event = createPropagationEvent({ | ||
name: `String.prototype.${method}`, | ||
name, | ||
moduleName: 'String', | ||
methodName: `prototype.${method}`, | ||
context: `${objInfo.value}.${method}()`, | ||
object: { | ||
@@ -134,0 +144,0 @@ value: objInfo.value, |
@@ -17,3 +17,3 @@ /* | ||
'use strict'; | ||
const { join } = require('@contrast/common'); | ||
const { join, inspect } = require('@contrast/common'); | ||
const { patchType } = require('../../common'); | ||
@@ -32,8 +32,19 @@ const { createSubsetTags } = require('../../../tag-utils'); | ||
function getPropagationEvent(data, res, objInfo, start) { | ||
const { name, args, result, hooked, orig } = data; | ||
const { name, args: origArgs, result, hooked, orig } = data; | ||
const tags = createSubsetTags(objInfo.tags, start, res.length - 1); | ||
if (!tags) return; | ||
const args = origArgs.map((arg) => { | ||
const argInfo = tracker.getData(arg); | ||
return { | ||
value: argInfo ? argInfo.value : inspect(arg), | ||
tracked: !!argInfo | ||
}; | ||
}); | ||
return createPropagationEvent({ | ||
name, | ||
moduleName: 'String', | ||
methodName: 'prototype.match', | ||
context: `'${objInfo.value}'.match(${join(args.map(a => a.value), ', ')})`, | ||
history: [objInfo], | ||
@@ -44,9 +55,3 @@ object: { | ||
}, | ||
args: args.map((arg) => { | ||
const argInfo = tracker.getData(arg); | ||
return { | ||
value: argInfo ? argInfo.value : arg.toString(), | ||
tracked: !!argInfo | ||
}; | ||
}), | ||
args, | ||
tags, | ||
@@ -53,0 +58,0 @@ result: { |
@@ -19,4 +19,7 @@ /* | ||
const { | ||
DataflowTag: { UNTRUSTED } | ||
DataflowTag: { UNTRUSTED }, | ||
match: origMatch, | ||
substring | ||
} = require('@contrast/common'); | ||
const { inspect, join } = require('@contrast/common'); | ||
const { patchType } = require('../../common'); | ||
@@ -67,3 +70,3 @@ const { createSubsetTags, createAppendTags } = require('../../../tag-utils'); | ||
].forEach(({ regex, replace }) => { | ||
if (ret && ret.match(regex)) { | ||
if (ret && origMatch(ret, regex)) { | ||
// If the match string is tracked, we can actually use the patched replace | ||
@@ -82,3 +85,3 @@ // to keep track of its tag ranges | ||
numberedGroupMatches.forEach((numberedGroup) => { | ||
const group = Number(numberedGroup.substring(1)); | ||
const group = Number(substring(numberedGroup, 1)); | ||
ret = origReplace.call(ret, numberedGroup, captureGroups[group - 1]); | ||
@@ -136,4 +139,5 @@ }); | ||
install() { | ||
const name = 'String.prototype.replace'; | ||
patcher.patch(String.prototype, 'replace', { | ||
name: 'String.prototype.replace', | ||
name, | ||
patchType, | ||
@@ -167,6 +171,17 @@ pre(data) { | ||
const { _replacementInfo, obj, args, result, hooked, orig } = data; | ||
const { _replacementInfo, obj, args: origArgs, result, hooked, orig } = data; | ||
const args = [{ | ||
value: inspect(origArgs[0]), | ||
tracked: !!tracker.getData(origArgs[0]) | ||
}, | ||
{ | ||
value: data._replacement, | ||
tracked: !!_replacementInfo | ||
}]; | ||
const event = createPropagationEvent({ | ||
name: 'String.prototype.replace', | ||
name, | ||
moduleName: 'String', | ||
methodName: 'prototype.replace', | ||
context: `'${obj}'.replace(${join(args.map(a => a.value), ', ')})`, | ||
history: Array.from(data._history), | ||
@@ -177,10 +192,3 @@ object: { | ||
}, | ||
args: [{ | ||
value: args[0].toString(), | ||
tracked: !!tracker.getData(args[0]) | ||
}, | ||
{ | ||
value: data._replacement, | ||
tracked: !!_replacementInfo | ||
}], | ||
args, | ||
result: { | ||
@@ -187,0 +195,0 @@ value: result, |
@@ -17,2 +17,3 @@ /* | ||
const { patchType } = require('../../common'); | ||
const { inspect, join } = require('@contrast/common'); | ||
const { createSubsetTags } = require('../../../tag-utils'); | ||
@@ -56,3 +57,3 @@ | ||
post(data) { | ||
const { name, args, obj, result, hooked, orig } = data; | ||
const { name, args: origArgs, obj, result, hooked, orig } = data; | ||
if (!result || !sources.getStore() || instrumentation.isLocked()) return; | ||
@@ -73,4 +74,12 @@ | ||
const args = origArgs.map((arg) => ({ | ||
value: inspect(arg), | ||
tracked: false | ||
})); | ||
const event = createPropagationEvent({ | ||
name, | ||
moduleName: 'String', | ||
methodName: 'prototype.slice', | ||
context: `'${objInfo.value}'.slice(${join(args.map(a => a.value), ', ')})`, | ||
history: [objInfo], | ||
@@ -81,6 +90,3 @@ object: { | ||
}, | ||
args: args.map((arg) => ({ | ||
value: arg.toString(), | ||
tracked: false | ||
})), | ||
args, | ||
result: { | ||
@@ -91,2 +97,4 @@ value: result, | ||
tags, | ||
source: 'O', | ||
target: 'R', | ||
stacktraceOpts: { | ||
@@ -93,0 +101,0 @@ constructorOpt: hooked, |
@@ -19,3 +19,3 @@ /* | ||
const { patchType } = require('../../common'); | ||
const { join } = require('@contrast/common'); | ||
const { join, inspect } = require('@contrast/common'); | ||
const { createSubsetTags } = require('../../../tag-utils'); | ||
@@ -41,7 +41,7 @@ | ||
post(data) { | ||
const { name, args, obj, result, hooked, orig } = data; | ||
const { name, args: origArgs, obj, result, hooked, orig } = data; | ||
if ( | ||
!obj || | ||
!result || | ||
args.length === 0 || | ||
origArgs.length === 0 || | ||
result.length === 0 || | ||
@@ -51,3 +51,3 @@ !sources.getStore() || | ||
instrumentation.isLocked() || | ||
(args.length === 1 && args[0] == null) | ||
(origArgs.length === 1 && origArgs[0] == null) | ||
) return; | ||
@@ -69,4 +69,14 @@ | ||
const args = origArgs.map((arg) => { | ||
const argInfo = tracker.getData(arg); | ||
return { | ||
value: argInfo ? argInfo.value : inspect(arg), | ||
tracked: !!argInfo | ||
}; | ||
}); | ||
const event = createPropagationEvent({ | ||
name, | ||
moduleName: 'String', | ||
methodName: 'prototype.slice', | ||
context: `'${objInfo.value}'.split(${join(args.map(a => a.value), ', ')})`, | ||
history: [objInfo], | ||
@@ -77,9 +87,3 @@ object: { | ||
}, | ||
args: args.map((arg) => { | ||
const argInfo = tracker.getData(arg); | ||
return { | ||
value: argInfo ? argInfo.value : arg.toString(), | ||
tracked: !!argInfo | ||
}; | ||
}), | ||
args, | ||
tags, | ||
@@ -86,0 +90,0 @@ result: { |
@@ -19,2 +19,3 @@ /* | ||
const { createSubsetTags } = require('../../../tag-utils'); | ||
const { join, inspect } = require('@contrast/common'); | ||
const { patchType } = require('../../common'); | ||
@@ -64,4 +65,4 @@ | ||
post(data) { | ||
const { obj, args, result, name, hooked, orig } = data; | ||
if (!result || !sources.getStore() || instrumentation.isLocked()) return; | ||
const { obj, args: origArgs, result, name, hooked, orig } = data; | ||
if (!result || !sources.getStore()?.assess || instrumentation.isLocked()) return; | ||
@@ -83,4 +84,11 @@ const objInfo = tracker.getData(obj); | ||
const args = origArgs.map((arg) => ({ | ||
value: inspect(arg), | ||
tracked: false | ||
})); | ||
const event = createPropagationEvent({ | ||
name, | ||
moduleName: 'String', | ||
methodName: 'prototype.substring', | ||
context: `'${objInfo.value}'.substring(${join(args.map(a => a.value), ', ')})`, | ||
history: [objInfo], | ||
@@ -91,6 +99,3 @@ object: { | ||
}, | ||
args: args.map((arg) => ({ | ||
value: arg.toString(), | ||
tracked: false | ||
})), | ||
args, | ||
result: { | ||
@@ -108,2 +113,7 @@ value: result, | ||
}); | ||
if (!event) { | ||
return; | ||
} | ||
const { extern } = tracker.track(result, event); | ||
@@ -110,0 +120,0 @@ |
@@ -63,2 +63,5 @@ /* | ||
name: `String.prototype.${methodName}`, | ||
moduleName: 'String', | ||
methodName: `prototype.${methodName}`, | ||
context: `'${obj}'.${methodName}()`, | ||
history, | ||
@@ -65,0 +68,0 @@ object: { |
@@ -37,4 +37,6 @@ /* | ||
install() { | ||
const name = 'global.unescape'; | ||
patcher.patch(global, 'unescape', { | ||
name: 'global.unescape', | ||
name, | ||
patchType, | ||
@@ -57,3 +59,6 @@ post(data) { | ||
const event = createPropagationEvent({ | ||
name: 'global.unescape', | ||
name, | ||
moduleName: 'global', | ||
methodName: 'unescape', | ||
context: `unescape('${argInfo.value}')`, | ||
object: { | ||
@@ -70,2 +75,4 @@ value: createObjectLabel('global'), | ||
history, | ||
source: 'P', | ||
target: 'R', | ||
removedTags: [WEAK_URL_ENCODED], | ||
@@ -72,0 +79,0 @@ stacktraceOpts: { |
@@ -37,4 +37,6 @@ /* | ||
['domainToASCII', 'domainToUnicode'].forEach((method) => { | ||
const name = `url.${method}`; | ||
patcher.patch(url, method, { | ||
name: `url.${method}`, | ||
name, | ||
patchType, | ||
@@ -53,3 +55,6 @@ post(data) { | ||
const event = createPropagationEvent({ | ||
name: `url.${method}`, | ||
name, | ||
moduleName: 'url', | ||
methodName: method, | ||
context: `url.${method}('${argInfo.value}')`, | ||
object: { | ||
@@ -56,0 +61,0 @@ value: createModuleLabel('url', version), |
@@ -33,5 +33,8 @@ /* | ||
name: `validator.${method}`, | ||
moduleName: 'validator', | ||
methodName: method, | ||
context: `validator.${method}('${trackingData.value}')`, | ||
history: [{ ...trackingData }], | ||
args: [{ | ||
value: data.args[0], | ||
value: trackingData.value, | ||
tracked: true | ||
@@ -63,4 +66,5 @@ }], | ||
const patchFn = typeof index === 'object' ? index.default : index; | ||
const name = `validator.${validator}`; | ||
return patcher.patch(patchFn, { | ||
name: `validator.${validator}`, | ||
name, | ||
patchType, | ||
@@ -67,0 +71,0 @@ post(data) { |
@@ -18,9 +18,12 @@ /* | ||
const { | ||
DataflowTag: { UNTRUSTED } | ||
DataflowTag: { UNTRUSTED }, | ||
join, | ||
Rule, | ||
isString, | ||
inspect, | ||
} = require('@contrast/common'); | ||
const { patchType } = require('../common'); | ||
const { Rule, isString, inspect } = require('@contrast/common'); | ||
module.exports = function (core) { | ||
module.exports = function(core) { | ||
const { | ||
@@ -41,11 +44,38 @@ depHooks, | ||
function commandCheck(name, command, secondArg, thirdArg, hooked) { | ||
function commandCheck( | ||
name, | ||
method, | ||
command, | ||
secondArg, | ||
thirdArg, | ||
hooked, | ||
orig | ||
) { | ||
const strInfo = tracker.getData(command); | ||
if (!strInfo || !isVulnerable(UNTRUSTED, safeTags, strInfo.tags)) return { | ||
strInfo: null, | ||
reported: false | ||
}; | ||
if (!strInfo || !isVulnerable(UNTRUSTED, safeTags, strInfo.tags)) | ||
return { | ||
strInfo: null, | ||
reported: false, | ||
}; | ||
const args = [ | ||
{ | ||
value: strInfo.value, | ||
tracked: true, | ||
}, | ||
secondArg && { | ||
value: inspect(secondArg), | ||
tracked: false, | ||
}, | ||
thirdArg && { | ||
value: inspect(thirdArg), | ||
tracked: false, | ||
}, | ||
].filter(Boolean); | ||
const event = createSinkEvent({ | ||
name, | ||
moduleName: 'child_process', | ||
methodName: method, | ||
context: `child_process.${method}(${join(args.map((a, idx) => idx === 0 ? `'${a.value}'` : a.value), ', ')})`, | ||
history: [strInfo], | ||
@@ -56,16 +86,3 @@ object: { | ||
}, | ||
args: [ | ||
{ | ||
value: strInfo.value, | ||
tracked: true, | ||
}, | ||
(secondArg && { | ||
value: inspect(secondArg), | ||
tracked: false | ||
}), | ||
(thirdArg && { | ||
value: inspect(thirdArg), | ||
tracked: false | ||
}) | ||
].filter(Boolean), | ||
args, | ||
tags: strInfo.tags, | ||
@@ -75,2 +92,3 @@ source: 'P0', | ||
constructorOpt: hooked, | ||
prependFrames: [orig], | ||
}, | ||
@@ -87,3 +105,3 @@ }); | ||
strInfo, | ||
reported: true | ||
reported: true, | ||
}; | ||
@@ -94,8 +112,17 @@ } | ||
strInfo, | ||
reported: false | ||
reported: false, | ||
}; | ||
} | ||
function argumentsCheck(name, command, commandInfo, args, options, hooked) { | ||
if (!Array.isArray(args) || !args?.length) return; | ||
function argumentsCheck( | ||
name, | ||
method, | ||
command, | ||
commandInfo, | ||
origArgs, | ||
options, | ||
hooked, | ||
orig | ||
) { | ||
if (!Array.isArray(origArgs) || !origArgs?.length) return; | ||
@@ -105,4 +132,4 @@ const trackedArgs = []; | ||
for (let i = 0; i < args.length; i++) { | ||
const trackData = tracker.getData(args[i]); | ||
for (let i = 0; i < origArgs.length; i++) { | ||
const trackData = tracker.getData(origArgs[i]); | ||
@@ -126,4 +153,21 @@ trackedArgs.push(trackData); | ||
const args = [ | ||
{ | ||
value: commandInfo?.value || command, | ||
tracked: !!commandInfo, | ||
}, | ||
{ | ||
value: inspect(origArgs), | ||
tracked: true, | ||
}, | ||
{ | ||
value: inspect(options), | ||
tracked: false, | ||
}, | ||
]; | ||
const event = createSinkEvent({ | ||
name, | ||
moduleName: 'child_process', | ||
methodName: method, | ||
context: `child_process.${method}(${join(args.map((a, idx) => idx === 0 ? `'${a.value}'` : a.value), ', ')})`, | ||
history: [trackedArgs[vulnerableArgIdx]], | ||
@@ -134,16 +178,3 @@ object: { | ||
}, | ||
args: [ | ||
{ | ||
value: commandInfo?.value || command, | ||
tracked: !!commandInfo, | ||
}, | ||
{ | ||
value: inspect(args), | ||
tracked: true | ||
}, | ||
{ | ||
value: inspect(options), | ||
tracked: false | ||
} | ||
], | ||
args, | ||
tags: trackedArgs[vulnerableArgIdx].tags, | ||
@@ -153,2 +184,3 @@ source: 'P1', | ||
contructorOpt: hooked, | ||
prependFrames: [orig], | ||
}, | ||
@@ -167,3 +199,3 @@ }); | ||
install() { | ||
depHooks.resolve({ name: 'child_process' }, cp => { | ||
depHooks.resolve({ name: 'child_process' }, (cp) => { | ||
['spawn', 'spawnSync'].forEach((method) => { | ||
@@ -183,8 +215,25 @@ const name = `child_process.${method}`; | ||
const cmdCheck = commandCheck(name, command, cpArgs, options, data.hooked); | ||
const cmdCheck = commandCheck( | ||
name, | ||
method, | ||
command, | ||
cpArgs, | ||
options, | ||
data.hooked, | ||
data.orig | ||
); | ||
if (cmdCheck.reported || !options?.shell) return; | ||
argumentsCheck(name, command, cmdCheck.strInfo, cpArgs, options, data.hooked); | ||
} | ||
argumentsCheck( | ||
name, | ||
method, | ||
command, | ||
cmdCheck.strInfo, | ||
cpArgs, | ||
options, | ||
data.hooked, | ||
data.orig | ||
); | ||
}, | ||
}); | ||
@@ -204,4 +253,12 @@ }); | ||
commandCheck(name, command, secondArg, thirdArg, data.hooked); | ||
} | ||
commandCheck( | ||
name, | ||
method, | ||
command, | ||
secondArg, | ||
thirdArg, | ||
data.hooked, | ||
data.orig | ||
); | ||
}, | ||
}); | ||
@@ -228,4 +285,13 @@ }); | ||
argumentsCheck(name, command, cmdInfo, cpArgs, options, data.hooked); | ||
} | ||
argumentsCheck( | ||
name, | ||
method, | ||
command, | ||
cmdInfo, | ||
cpArgs, | ||
options, | ||
data.hooked, | ||
data.orig | ||
); | ||
}, | ||
}); | ||
@@ -232,0 +298,0 @@ }); |
@@ -35,3 +35,3 @@ /* | ||
module.exports = function (core) { | ||
module.exports = function(core) { | ||
const { | ||
@@ -63,3 +63,3 @@ depHooks, | ||
unvalidatedRedirect.install = function () { | ||
unvalidatedRedirect.install = function() { | ||
depHooks.resolve({ name: 'express', file: 'lib/response' }, (Response) => { | ||
@@ -97,3 +97,5 @@ const name = 'Express.Response.location'; | ||
history: [strInfo], | ||
name: 'Express.Response.location', | ||
name, | ||
moduleName: 'express', | ||
methodName: 'Response.location', | ||
object: { | ||
@@ -111,2 +113,3 @@ tracked: false, | ||
constructorOpt: data.hooked, | ||
prependFrames: [data.orig] | ||
}, | ||
@@ -113,0 +116,0 @@ }); |
@@ -53,3 +53,3 @@ /* | ||
module.exports = function (core) { | ||
module.exports = function(core) { | ||
const { | ||
@@ -81,5 +81,5 @@ config, | ||
unvalidatedRedirect.install = function () { | ||
unvalidatedRedirect.install = function() { | ||
const name = 'fastify.Reply.prototype.redirect'; | ||
depHooks.resolve({ name: 'fastify', file: 'lib/reply' }, (Reply, version) => { | ||
depHooks.resolve({ name: 'fastify', file: 'lib/reply' }, (Reply) => { | ||
patcher.patch(Reply.prototype, 'redirect', { | ||
@@ -124,3 +124,5 @@ name, | ||
history: [strInfo], | ||
name: 'fastify.reply.redirect', | ||
name, | ||
moduleName: 'fastify', | ||
methodName: 'reply.redirect', | ||
object: { | ||
@@ -138,2 +140,3 @@ tracked: false, | ||
constructorOpt: data.hooked, | ||
prependFrames: [data.orig] | ||
}, | ||
@@ -140,0 +143,0 @@ }); |
@@ -18,5 +18,18 @@ /* | ||
const { patchType } = require('../common'); | ||
const { FS_METHODS, Rule, isString, DataflowTag: { URL_ENCODED, LIMITED_CHARS, ALPHANUM_SPACE_HYPHEN, SAFE_PATH, UNTRUSTED } } = require('@contrast/common'); | ||
const { | ||
FS_METHODS, | ||
Rule, | ||
isString, | ||
DataflowTag: { | ||
URL_ENCODED, | ||
LIMITED_CHARS, | ||
ALPHANUM_SPACE_HYPHEN, | ||
SAFE_PATH, | ||
UNTRUSTED, | ||
}, | ||
inspect, | ||
join, | ||
} = require('@contrast/common'); | ||
module.exports = function (core) { | ||
module.exports = function(core) { | ||
const { | ||
@@ -35,3 +48,8 @@ depHooks, | ||
const safeTags = [URL_ENCODED, LIMITED_CHARS, ALPHANUM_SPACE_HYPHEN, SAFE_PATH]; | ||
const safeTags = [ | ||
URL_ENCODED, | ||
LIMITED_CHARS, | ||
ALPHANUM_SPACE_HYPHEN, | ||
SAFE_PATH, | ||
]; | ||
@@ -46,3 +64,4 @@ function getValues(indices, args) { | ||
const pre = (name, indices) => (data) => { | ||
const pre = (name, method, moduleName = 'fs', fullMethodName = '') => (data) => { | ||
const { name: methodName, indices } = method; | ||
const store = sources.getStore()?.assess; | ||
@@ -54,6 +73,12 @@ if (!store) return; | ||
const args = []; | ||
const args = values.map((v) => { | ||
const strInfo = tracker.getData(v); | ||
return { | ||
value: strInfo ? strInfo.value : v, | ||
isTracked: !!strInfo, | ||
strInfo | ||
}; | ||
}); | ||
for (let i = 0; i < values.length; i++) { | ||
const strInfo = tracker.getData(values[i]); | ||
args.push({ value: strInfo ? strInfo.value : values[i], isTracked: !!strInfo }); | ||
const { strInfo } = args[i]; | ||
if (!strInfo || !isVulnerable(UNTRUSTED, safeTags, strInfo.tags)) { | ||
@@ -65,2 +90,8 @@ continue; | ||
name, | ||
moduleName, | ||
methodName: fullMethodName || methodName, | ||
context: `${name}(${join( | ||
args.map((a) => inspect(a.value)), | ||
', ' | ||
)})`, | ||
history: [strInfo], | ||
@@ -71,3 +102,3 @@ object: { | ||
}, | ||
args, | ||
args: args.map(({ value, isTracked }) => ({ value, isTracked })), | ||
tags: strInfo.tags, | ||
@@ -77,2 +108,3 @@ source: `P${i}`, | ||
contructorOpt: data.hooked, | ||
prependFrames: [data.orig], | ||
}, | ||
@@ -100,3 +132,3 @@ }); | ||
patchType, | ||
pre: pre(name, method.indices) | ||
pre: pre(name, method), | ||
}); | ||
@@ -112,3 +144,3 @@ } | ||
patchType, | ||
pre: pre(name, method.indices) | ||
pre: pre(name, method, 'fs', syncName), | ||
}); | ||
@@ -123,3 +155,3 @@ } | ||
patchType, | ||
pre: pre(name, method.indices) | ||
pre: pre(name, method, 'fs.promises'), | ||
}); | ||
@@ -137,3 +169,3 @@ } | ||
patchType, | ||
pre: pre(name, method.indices) | ||
pre: pre(name, method, 'fsPromises'), | ||
}); | ||
@@ -140,0 +172,0 @@ } |
@@ -89,5 +89,7 @@ /* | ||
}], | ||
context: `res.${method}(${strInfo.value})`, | ||
context: `res.${method}('${strInfo.value}')`, | ||
history: [strInfo], | ||
name, | ||
moduleName: 'http', | ||
methodName: `ServerResponse.prototype.${method}`, | ||
object: { | ||
@@ -103,3 +105,4 @@ tracked: false, | ||
stacktraceOpts: { | ||
constructorOpt: data.hooked | ||
constructorOpt: data.hooked, | ||
prependFrames: [data.orig] | ||
}, | ||
@@ -106,0 +109,0 @@ tags: strInfo.tags, |
@@ -35,3 +35,3 @@ /* | ||
module.exports = function (core) { | ||
module.exports = function(core) { | ||
const { | ||
@@ -63,7 +63,7 @@ depHooks, | ||
unvalidatedRedirect.install = function () { | ||
unvalidatedRedirect.install = function() { | ||
depHooks.resolve({ name: 'koa', file: 'lib/response', version: '<2.9.0' }, (Response) => { | ||
const name = 'Koa.Response.redirect'; | ||
patcher.patch(Response, 'redirect', { | ||
name: 'Koa.Response.redirect', | ||
name, | ||
patchType, | ||
@@ -109,3 +109,5 @@ pre(data) { | ||
history: [strInfo], | ||
name: 'Koa.Response.redirect', | ||
name, | ||
moduleName: 'koa', | ||
methodName: 'Response.redirect', | ||
object: { | ||
@@ -123,2 +125,3 @@ tracked: false, | ||
constructorOpt: data.hooked, | ||
prependFrames: [data.orig] | ||
}, | ||
@@ -125,0 +128,0 @@ }); |
@@ -105,2 +105,4 @@ /* | ||
context: `marsdb.Collection.${method}(${args.map((a) => a.value)})`, | ||
moduleName: 'marsdb', | ||
methodName: `Collection.prototype.${method}`, | ||
history: [strInfo], | ||
@@ -116,2 +118,3 @@ object: { | ||
constructorOpt: data.hooked, | ||
prependFrames: [data.orig] | ||
}, | ||
@@ -118,0 +121,0 @@ tags: strInfo.tags, |
@@ -289,3 +289,3 @@ /* | ||
args, | ||
context: `${objName}.${method}(${args.map((a) => a.value)})`, | ||
context: `${objName}.${method}(${args.map((a, idx) => isString(origArgs[idx]) ? `'${a.value}'` : a.value)})`, | ||
history: [strInfo], | ||
@@ -297,2 +297,4 @@ object: { | ||
name, | ||
moduleName: 'mongodb', | ||
methodName: `${entity}.prototype.${method}`, | ||
result: { | ||
@@ -299,0 +301,0 @@ tracked: false, |
@@ -33,3 +33,3 @@ /* | ||
module.exports = function (core) { | ||
module.exports = function(core) { | ||
const { | ||
@@ -48,3 +48,3 @@ depHooks, | ||
const pre = (name, obj, version) => (data) => { | ||
const pre = (name, method, obj, version) => (data) => { | ||
const store = sources.getStore()?.assess; | ||
@@ -65,2 +65,5 @@ if ( | ||
name, | ||
moduleName: 'mssql', | ||
methodName: `PreparedStatement.prototype.${method}`, | ||
context: `mssql.PreparedStatement.${method}('${strInfo.value}')`, | ||
history: [strInfo], | ||
@@ -81,2 +84,3 @@ object: { | ||
contructorOpt: data.hooked, | ||
prependFrames: [data.orig] | ||
}, | ||
@@ -103,2 +107,3 @@ }); | ||
'mssql/lib/base/prepared-statement.prototype.prepare', | ||
'prepare', | ||
'PreparedStatement', | ||
@@ -119,2 +124,3 @@ version, | ||
'mssql/lib/base/request.prototype.batch', | ||
'batch', | ||
'Request', | ||
@@ -130,2 +136,3 @@ version, | ||
'mssql/lib/base/request.prototype.query', | ||
'query', | ||
'Request', | ||
@@ -132,0 +139,0 @@ version, |
@@ -31,2 +31,3 @@ /* | ||
}, | ||
inspect | ||
} = require('@contrast/common'); | ||
@@ -43,3 +44,3 @@ | ||
module.exports = function (core) { | ||
module.exports = function(core) { | ||
const { | ||
@@ -68,3 +69,3 @@ depHooks, | ||
const pre = (module, file, obj) => (data) => { | ||
const pre = (module, file, obj, method) => (data) => { | ||
const store = sources.getStore()?.assess; | ||
@@ -87,2 +88,5 @@ if ( | ||
name: `${module}/${file}`, | ||
moduleName: module, | ||
methodName: `prototype.${method}`, | ||
context: `${module}.${method}(${inspect(data.args[0])})`, | ||
history: [strInfo], | ||
@@ -103,2 +107,3 @@ object: { | ||
contructorOpt: data.hooked, | ||
prependFrames: [data.orig] | ||
}, | ||
@@ -123,3 +128,3 @@ }); | ||
patchType, | ||
pre: pre('mysql', 'lib/Connection.query', 'Connection') | ||
pre: pre('mysql', 'lib/Connection.query', 'Connection', 'query') | ||
}); | ||
@@ -135,3 +140,3 @@ }, | ||
patchType, | ||
pre: pre('mysql2', `lib/connection.Connection.${method}`, 'connection') | ||
pre: pre('mysql2', `lib/connection.Connection.${method}`, 'connection', method) | ||
}); | ||
@@ -138,0 +143,0 @@ }); |
@@ -22,7 +22,7 @@ /* | ||
Rule: { SQL_INJECTION: ruleId }, | ||
isString | ||
isString, | ||
} = require('@contrast/common'); | ||
const { filterSafeTags, patchType } = require('../common'); | ||
module.exports = function (core) { | ||
module.exports = function(core) { | ||
const { | ||
@@ -78,2 +78,4 @@ config, | ||
name: methodSignature, | ||
moduleName: `${methodSignature.includes('pool') ? 'pg-pool' : 'pg'}`, | ||
methodName: 'Connection.prototype.query', | ||
object: { | ||
@@ -91,2 +93,3 @@ tracked: false, | ||
constructorOpt: data.hooked, | ||
prependFrames: [data.orig] | ||
}, | ||
@@ -114,3 +117,3 @@ }); | ||
postgres.install = function () { | ||
postgres.install = function() { | ||
const pgClientQueryPatchName = 'pg.Client.prototype.query'; | ||
@@ -117,0 +120,0 @@ depHooks.resolve( |
@@ -31,3 +31,3 @@ /* | ||
module.exports = function (core) { | ||
module.exports = function(core) { | ||
const { | ||
@@ -58,3 +58,3 @@ depHooks, | ||
sequelize.install = function () { | ||
sequelize.install = function() { | ||
const sequelizeQueryPatchName = 'sequelize.prototype.query'; | ||
@@ -74,3 +74,3 @@ depHooks.resolve({ name: 'sequelize' }, (sequelize) => { | ||
const queryInfo = tracker.getData(query); | ||
const isVulnerableQuery = isVulnerable(requiredTag, safeTags, queryInfo.tags); | ||
const isVulnerableQuery = queryInfo && isVulnerable(requiredTag, safeTags, queryInfo.tags); | ||
@@ -100,4 +100,4 @@ if (queryInfo && !isVulnerableQuery && config.assess.safe_positives.enable) { | ||
const contextArgs = args[1] | ||
? `${sqlValue}, ${inspectedOptions}` | ||
: sqlValue; | ||
? `'${sqlValue}', ${inspectedOptions}` | ||
: `'${sqlValue}'`; | ||
@@ -111,2 +111,4 @@ const reportedArgs = [{ value: sqlValue, tracked: true }]; | ||
name: sequelizeQueryPatchName, | ||
moduleName: 'sequelize', | ||
methodName: 'prototype.query', | ||
history: [queryInfo], | ||
@@ -113,0 +115,0 @@ object: { |
@@ -32,3 +32,3 @@ /* | ||
module.exports = function (core) { | ||
module.exports = function(core) { | ||
const { | ||
@@ -47,3 +47,3 @@ depHooks, | ||
const pre = (name) => (data) => { | ||
const pre = (name, method) => (data) => { | ||
const store = sources.getStore()?.assess; | ||
@@ -64,2 +64,5 @@ if ( | ||
name, | ||
moduleName: 'sqlite3', | ||
methodName: `Database.prototype.${method}`, | ||
context: `db.${method}('${strInfo.value}')`, | ||
history: [strInfo], | ||
@@ -80,2 +83,3 @@ object: { | ||
contructorOpt: data.hooked, | ||
prependFrames: [data.orig] | ||
}, | ||
@@ -100,3 +104,3 @@ }); | ||
patchType, | ||
pre: pre(name) | ||
pre: pre(name, method) | ||
}); | ||
@@ -103,0 +107,0 @@ }); |
@@ -22,2 +22,3 @@ /* | ||
isString, | ||
join, | ||
} = require('@contrast/common'); | ||
@@ -119,3 +120,3 @@ | ||
traverse(_data, (path, fieldName, value, obj) => { | ||
const pathName = path.join('.'); | ||
const pathName = join(path, '.'); | ||
@@ -122,0 +123,0 @@ if (sourceContext.sourceEventsCount >= max) { |
@@ -83,3 +83,3 @@ /* | ||
if (toLowerCase(name) === 'content-type' && value) { | ||
store.assess.responseData.contentType = value; | ||
scopes.sources.getStore().assess.responseData.contentType = value; | ||
} | ||
@@ -86,0 +86,0 @@ } |
@@ -137,2 +137,25 @@ /* | ||
function createOverlappingTags(tags, startIndex, endIndex) { | ||
const overlappingTags = {}; | ||
Object.entries(tags).forEach(([tag, tagRanges]) => { | ||
const overlappingRanges = []; | ||
for (let i = 0; i < tagRanges.length; i += 2) { | ||
const start = tagRanges[i]; | ||
const end = tagRanges[i + 1]; | ||
if (end >= startIndex && start <= endIndex) { | ||
overlappingRanges.push([start, end]); | ||
} | ||
} | ||
if (overlappingRanges.length > 0) { | ||
overlappingTags[tag] = overlappingRanges; | ||
} | ||
}); | ||
return overlappingTags; | ||
} | ||
/** | ||
@@ -189,3 +212,4 @@ * assumes: | ||
createFullLengthCopyTags, | ||
createMergedTags | ||
createMergedTags, | ||
createOverlappingTags | ||
}; |
@@ -37,3 +37,4 @@ /* | ||
if (typeof value === 'string') { | ||
return distringuish.getProperties(value); | ||
const props = distringuish.getProperties(value); | ||
return props?.untracked ? null : props; | ||
} | ||
@@ -130,7 +131,6 @@ | ||
if (props) { | ||
Object.assign(props, { | ||
history: [], | ||
tags: {}, | ||
}); | ||
delete props.resultTracked; | ||
for (const key of Object.keys(props)) { | ||
delete props[key]; | ||
} | ||
props.untracked = true; | ||
} | ||
@@ -137,0 +137,0 @@ return distringuish.internalize(value); |
@@ -19,2 +19,3 @@ /* | ||
const { callChildComponentMethodsSync } = require('@contrast/common'); | ||
const sessionConfiguration = require('./session-configuration'); | ||
const dataflow = require('./dataflow'); | ||
@@ -30,2 +31,3 @@ const responseScanning = require('./response-scanning'); | ||
// 1. dataflow | ||
sessionConfiguration(core); | ||
dataflow(core); | ||
@@ -32,0 +34,0 @@ responseScanning(core); |
@@ -18,3 +18,3 @@ /* | ||
const { join, substring, toLowerCase, split, trim } = require('@contrast/common'); | ||
const { join, substring, toLowerCase, split, trim, replace } = require('@contrast/common'); | ||
@@ -36,3 +36,3 @@ // | ||
return (string && reHasUnescapedHtml.test(string)) | ||
? string.replace(reUnescapedHtml, (chr) => htmlEscapes[chr]) | ||
? replace(string, reUnescapedHtml, (chr) => htmlEscapes[chr]) | ||
: (string || ''); | ||
@@ -39,0 +39,0 @@ } |
{ | ||
"name": "@contrast/assess", | ||
"version": "1.8.0", | ||
"version": "1.9.0", | ||
"description": "", | ||
@@ -18,5 +18,5 @@ "main": "lib/index.js", | ||
"@contrast/scopes": "1.4.0", | ||
"@contrast/common": "1.11.0", | ||
"@contrast/common": "1.12.0", | ||
"parseurl": "^1.3.3" | ||
} | ||
} |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
338288
98
9612
+ Added@contrast/common@1.12.0(transitive)
- Removed@contrast/common@1.11.0(transitive)
Updated@contrast/common@1.12.0