Socket
Socket
Sign inDemoInstall

@contrast/assess

Package Overview
Dependencies
Maintainers
14
Versions
49
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@contrast/assess - npm Package Compare versions

Comparing version 1.8.0 to 1.9.0

lib/dataflow/propagation/install/contrast-methods/number.js

30

lib/dataflow/event-factory.js

@@ -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"
}
}
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc