Socket
Socket
Sign inDemoInstall

@contrast/assess

Package Overview
Dependencies
Maintainers
9
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.27.2 to 1.28.0

6

lib/constants.js

@@ -19,5 +19,5 @@ /*

const InstrumentationType = {
SOURCE: 'source',
PROPAGATOR: 'propagator',
RULE: 'rule',
SOURCE: 'SOURCE',
PROPAGATOR: 'PROPAGATOR',
RULE: 'RULE',
};

@@ -24,0 +24,0 @@

@@ -18,13 +18,12 @@ /*

const {
createAppendTags
} = require('../../tag-utils');
const { isString, join, inspect } = require('@contrast/common');
const { InstrumentationType: { PROPAGATOR } } = require('../../../constants');
const { createAppendTags } = require('../../tag-utils');
const { patchType } = require('../common');
const { isString, join, inspect } = require('@contrast/common');
module.exports = function(core) {
const {
scopes: { sources, instrumentation },
patcher,
assess: {
getSourceContext,
eventFactory: { createPropagationEvent },

@@ -75,3 +74,3 @@ dataflow: { tracker }

const { args: origArgs, obj, result, hooked, orig } = data;
if (!result || !sources.getStore()?.assess || instrumentation.isLocked()) return;
if (!result || !(getSourceContext(PROPAGATOR))) return;

@@ -78,0 +77,0 @@ const resultInfo = tracker.getData(result);

@@ -17,2 +17,3 @@ /*

const { InstrumentationType: { PROPAGATOR } } = require('../../../constants');
const { patchType } = require('../common');

@@ -23,2 +24,3 @@

assess: {
getSourceContext,
eventFactory,

@@ -40,3 +42,3 @@ dataflow: { tracker }

if (!result) return;
if (!result || !getSourceContext(PROPAGATOR)) return;

@@ -43,0 +45,0 @@ const bufferInfo = tracker.getData(obj);

@@ -19,12 +19,10 @@ /*

const util = require('util');
const {
createAppendTags
} = require('../../../tag-utils');
const { patchType } = require('../../common');
const { InstrumentationType: { PROPAGATOR } } = require('../../../../constants');
const { createAppendTags } = require('../../../tag-utils');
module.exports = function(core) {
const {
scopes: { instrumentation, sources },
patcher,
assess: {
getSourceContext,
eventFactory: { createPropagationEvent },

@@ -36,84 +34,89 @@ dataflow: { tracker }

const inspect = patcher.unwrap(util.inspect);
const origSym = Symbol('ContrastMethods.add.orig');
return core.assess.dataflow.propagation.contrastMethodsInstrumentation.add = {
install() {
patcher.patch(global.ContrastMethods, 'add', {
name: 'ContrastMethods.add',
patchType,
post(data) {
const { args, result, hooked } = data;
if (!result || !sources.getStore()?.assess || instrumentation.isLocked()) return;
// + is fast and typically called often. therefore we patch ContrastMethods.add
// manually instead of using patcher. this propagator is the only
// patch for it, so we don't have to worry about managing patch execution order
// (which patcher would do).
const { add } = global.ContrastMethods;
global.ContrastMethods.add = function(...args) {
// first get result, then following logic acts as post-hook in patcher speak
const result = add(...args);
const rInfo = tracker.getData(result);
if (rInfo) {
// this may happen w/ '' + 'tracked' => 'tracked'
return;
}
if (!result || !getSourceContext(PROPAGATOR)) return result;
const leftStringInfo = tracker.getData(args[0]);
const rightStringInfo = tracker.getData(args[1]);
const rInfo = tracker.getData(result);
if (rInfo) {
// this may happen w/ '' + 'tracked' => 'tracked'
return result;
}
let newTags = {};
const history = [];
const leftStringInfo = tracker.getData(args[0]);
const rightStringInfo = tracker.getData(args[1]);
if (leftStringInfo) {
history.push(leftStringInfo);
newTags = leftStringInfo.tags || {};
}
let newTags = {};
const history = [];
if (rightStringInfo) {
history.push(rightStringInfo);
newTags = createAppendTags(newTags, rightStringInfo.tags, args[0].length);
}
if (leftStringInfo) {
history.push(leftStringInfo);
newTags = leftStringInfo.tags || {};
}
if (history.length) {
const leftArg = leftStringInfo ? leftStringInfo.value : args[0];
const rightArg = rightStringInfo ? rightStringInfo.value : args[1];
const event = createPropagationEvent({
args: [
{
tracked: !!leftStringInfo,
value: leftArg
},
{
tracked: !!rightStringInfo,
value: rightArg,
}
],
context: `${inspect(leftArg)} + ${inspect(rightArg)}`,
moduleName: 'global',
methodName: 'ContrastMethods.add',
history,
object: {
value: 'String Addition',
tracked: false
if (rightStringInfo) {
history.push(rightStringInfo);
newTags = createAppendTags(newTags, rightStringInfo.tags, args[0].length);
}
if (history.length) {
const leftArg = leftStringInfo ? leftStringInfo.value : args[0];
const rightArg = rightStringInfo ? rightStringInfo.value : args[1];
const event = createPropagationEvent({
args: [
{
tracked: !!leftStringInfo,
value: leftArg
},
name: 'ContrastMethods.add',
result: {
value: result,
tracked: true
},
source: 'P',
stacktraceOpts: {
constructorOpt: hooked,
},
tags: newTags,
target: 'R',
});
{
tracked: !!rightStringInfo,
value: rightArg,
}
],
context: `${inspect(leftArg)} + ${inspect(rightArg)}`,
moduleName: 'global',
methodName: 'ContrastMethods.add',
history,
object: {
value: 'String Addition',
tracked: false
},
name: 'ContrastMethods.add',
result: {
value: result,
tracked: true
},
source: 'P',
stacktraceOpts: {
constructorOpt: add,
},
tags: newTags,
target: 'R',
});
if (!event) return;
if (event) {
const { extern } = tracker.track(result, event);
if (extern) {
data.result = extern;
}
if (extern) return extern;
}
}
});
return result;
};
global.ContrastMethods.add[origSym] = add;
},
uninstall() {
global.ContrastMethods.add = patcher.unwrap(global.ContrastMethods.add);
const orig = global.ContrastMethods.add[origSym];
if (orig) global.ContrastMethods.add = orig;
},
};
};

@@ -19,2 +19,3 @@ /*

const { isString } = require('@contrast/common');
const { InstrumentationType: { PROPAGATOR } } = require('../../../../constants');
const { patchType } = require('../../common');

@@ -25,5 +26,5 @@

logger,
scopes: { instrumentation, sources },
patcher,
assess: {
getSourceContext,
dataflow: { tracker }

@@ -43,9 +44,7 @@ }

if (
!tracker.getData(value) ||
isNaN(result) ||
!value ||
!isString(value) ||
!sources.getStore()?.assess ||
instrumentation.isLocked() ||
// why not just do this first? won't need check for NaN, !value, !isString, etc.
!tracker.getData(value)
!getSourceContext(PROPAGATOR)
) return;

@@ -52,0 +51,0 @@

@@ -19,2 +19,3 @@ /*

const { DataflowTag } = require('@contrast/common');
const { InstrumentationType: { PROPAGATOR } } = require('../../../../constants');
const { patchType } = require('../../common');

@@ -33,5 +34,5 @@

const {
scopes: { sources, instrumentation },
patcher,
assess: {
getSourceContext,
eventFactory: { createPropagationEvent },

@@ -49,3 +50,3 @@ dataflow: { tracker },

post(data) {
if (!data.result || !sources.getStore() || instrumentation.isLocked()) return;
if (!data.result || !getSourceContext(PROPAGATOR)) return;

@@ -52,0 +53,0 @@ const arg = data.args[0];

@@ -18,2 +18,3 @@ /*

const { InstrumentationType: { PROPAGATOR } } = require('../../../../constants');
const { patchType } = require('../../common');

@@ -24,2 +25,3 @@

assess: {
getSourceContext,
eventFactory: { createPropagationEvent },

@@ -29,3 +31,2 @@ dataflow: { tracker },

patcher,
scopes: { sources, instrumentation },
} = core;

@@ -39,7 +40,3 @@

post(data) {
if (
!data.result ||
!sources.getStore()?.assess ||
instrumentation.isLocked()
) {
if (!data.result || !getSourceContext(PROPAGATOR)) {
return;

@@ -46,0 +43,0 @@ }

@@ -18,6 +18,5 @@ /*

const {
createAppendTags
} = require('../../../tag-utils');
const { join, inspect } = require('@contrast/common');
const { InstrumentationType: { PROPAGATOR } } = require('../../../../constants');
const { createAppendTags } = require('../../../tag-utils');
const { patchType } = require('../../common');

@@ -27,5 +26,5 @@

const {
scopes: { sources, instrumentation },
patcher,
assess: {
getSourceContext,
eventFactory: { createPropagationEvent },

@@ -45,3 +44,3 @@ dataflow: { tracker }

const { args, obj, result, hooked, orig } = data;
if (!result || !sources.getStore()?.assess || instrumentation.isLocked()) return;
if (!result || !getSourceContext(PROPAGATOR)) return;

@@ -48,0 +47,0 @@ const rInfo = tracker.getData(result);

@@ -18,6 +18,5 @@ /*

const {
createAppendTags
} = require('../../../tag-utils');
const { inspect } = require('@contrast/common');
const { InstrumentationType: { PROPAGATOR } } = require('../../../../constants');
const { createAppendTags } = require('../../../tag-utils');
const { patchType } = require('../../common');

@@ -37,5 +36,5 @@ const htmlTagsLengths = {

const {
scopes: { sources, instrumentation },
patcher,
assess: {
getSourceContext,
eventFactory: { createPropagationEvent },

@@ -70,3 +69,3 @@ dataflow: { tracker }

const { args, obj, result, hooked, orig } = data;
if (!result || !sources.getStore()?.assess || instrumentation.isLocked()) return;
if (!result || !getSourceContext(PROPAGATOR)) return;

@@ -128,3 +127,3 @@ const objInfo = tracker.getData(obj);

const { obj, result, hooked, orig } = data;
if (!result || !sources.getStore()?.assess || instrumentation.isLocked()) return;
if (!result || !getSourceContext(PROPAGATOR)) return;

@@ -131,0 +130,0 @@ const objInfo = tracker.getData(obj);

@@ -18,10 +18,11 @@ /*

const { inspect } = require('@contrast/common');
const { InstrumentationType: { PROPAGATOR } } = require('../../../../constants');
const { createSubsetTags } = require('../../../tag-utils');
const { patchType } = require('../../common');
const { createSubsetTags } = require('../../../tag-utils');
module.exports = function(core) {
const {
scopes: { sources, instrumentation },
patcher,
assess: {
getSourceContext,
eventFactory: { createPropagationEvent },

@@ -79,3 +80,3 @@ dataflow: {

return (stringInstrumentation.matchAll = {
return stringInstrumentation.matchAll = {
install() {

@@ -92,4 +93,3 @@ patcher.patch(String.prototype, 'matchAll', {

typeof obj !== 'string' ||
!sources.getStore()?.assess ||
instrumentation.isLocked()
!getSourceContext(PROPAGATOR)
)

@@ -239,3 +239,3 @@ return origFn();

},
});
};
};

@@ -21,7 +21,9 @@ /*

match: origMatch,
inspect,
join,
substring
} = require('@contrast/common');
const { inspect, join } = require('@contrast/common');
const { InstrumentationType: { PROPAGATOR } } = require('../../../../constants');
const { createSubsetTags, createAppendTags } = require('../../../tag-utils');
const { patchType } = require('../../common');
const { createSubsetTags, createAppendTags } = require('../../../tag-utils');

@@ -32,6 +34,6 @@ module.exports = function(core) {

assess: {
getSourceContext,
eventFactory: { createPropagationEvent },
dataflow: { tracker }
},
scopes: { sources, instrumentation }
} = core;

@@ -146,3 +148,3 @@

pre(data) {
if (!sources.getStore()?.assess || instrumentation.isLocked()) return;
if (!getSourceContext(PROPAGATOR)) return;

@@ -161,4 +163,2 @@ // setup state

if (
!sources.getStore()?.assess ||
instrumentation.isLocked() ||
!data.result ||

@@ -165,0 +165,0 @@ // todo: can we reuse this optimization in other propagators? e.g those performing substring-like operations

@@ -16,11 +16,12 @@ /*

'use strict';
const { patchType } = require('../../common');
const { inspect, join } = require('@contrast/common');
const { InstrumentationType: { PROPAGATOR } } = require('../../../../constants');
const { createSubsetTags } = require('../../../tag-utils');
const { patchType } = require('../../common');
module.exports = function(core) {
const {
scopes: { sources, instrumentation },
patcher,
assess: {
getSourceContext,
eventFactory: { createPropagationEvent },

@@ -59,3 +60,3 @@ dataflow: { tracker }

const { name, args: origArgs, obj, result, hooked, orig } = data;
if (!result || !sources.getStore() || instrumentation.isLocked()) return;
if (!result || !getSourceContext(PROPAGATOR)) return;

@@ -62,0 +63,0 @@ const objInfo = tracker.getData(obj);

@@ -18,12 +18,12 @@ /*

const { patchType } = require('../../common');
const { join, inspect } = require('@contrast/common');
const { InstrumentationType: { PROPAGATOR } } = require('../../../../constants');
const { createSubsetTags } = require('../../../tag-utils');
const { patchType } = require('../../common');
module.exports = function(core) {
const {
scopes: { sources, instrumentation },
patcher,
assess: {
getSourceContext,
eventFactory,

@@ -48,6 +48,5 @@ dataflow: { tracker }

result.length === 0 ||
!sources.getStore() ||
typeof obj !== 'string' ||
instrumentation.isLocked() ||
(origArgs.length === 1 && origArgs[0] == null)
(origArgs.length === 1 && origArgs[0] == null) ||
!getSourceContext(PROPAGATOR)
) return;

@@ -54,0 +53,0 @@

@@ -18,4 +18,5 @@ /*

const { join, inspect } = require('@contrast/common');
const { InstrumentationType: { PROPAGATOR } } = require('../../../../constants');
const { createSubsetTags } = require('../../../tag-utils');
const { join, inspect } = require('@contrast/common');
const { patchType } = require('../../common');

@@ -25,5 +26,5 @@

const {
scopes: { sources, instrumentation },
patcher,
assess: {
getSourceContext,
eventFactory: { createPropagationEvent },

@@ -68,3 +69,3 @@ dataflow: { tracker }

const { obj, args: origArgs, result, name, hooked, orig } = data;
if (!result || !sources.getStore()?.assess || instrumentation.isLocked()) return;
if (!result || !getSourceContext(PROPAGATOR)) return;

@@ -131,2 +132,1 @@ const objInfo = tracker.getData(obj);

};

@@ -18,5 +18,4 @@ /*

const {
createSubsetTags,
} = require('../../../tag-utils');
const { InstrumentationType: { PROPAGATOR } } = require('../../../../constants');
const { createSubsetTags } = require('../../../tag-utils');
const { patchType } = require('../../common');

@@ -26,5 +25,5 @@

const {
scopes: { sources, instrumentation },
patcher,
assess: {
getSourceContext,
eventFactory: { createPropagationEvent },

@@ -39,3 +38,3 @@ dataflow: { tracker }

if (!result?.length || !sources.getStore()?.assess || instrumentation.isLocked()) {
if (!result?.length || !getSourceContext(PROPAGATOR)) {
return;

@@ -42,0 +41,0 @@ }

@@ -239,2 +239,45 @@ /*

/**
* Truncate `arg` values for reporting and get the adjusted `tags`.
* If an argument isn't directly relevant to the vulnerability, we report it by its type.
* If it is relevant, we truncate the value if it is an object or array, but not if it is a string.
* Ex1: Array truncations will look like `[...'<key>':'<value>'...]`
* Ex2: Object truncations will look like `{...'<key>':'<value>'...}`
* In the above examples, `key` will be the last value in the path array, and `value` should be the
* containing the injection. So whether the argument is a string or an object, the actual string value
* leading to the injection will not be truncated.
*/
function getAdjustedFields(origArgs, vulnInfo, vulnArgIdx) {
const { path, strInfo } = vulnInfo;
const coercedArgs = [];
let prefix = '';
let suffix = '';
if (path) {
let openChar, closeChar;
if (Array.isArray(origArgs[vulnArgIdx])) {
openChar = '[';
closeChar = ']';
} else {
openChar = '{';
closeChar = '}';
}
prefix = `${openChar}...'${path[path.length - 1]}':'`;
suffix = `'...${closeChar}`;
}
for (let i = 0; i < origArgs.length; i++) {
if (i === vulnArgIdx) {
coercedArgs.push({ value: `${prefix}${strInfo.value}${suffix}`, tracked: true });
} else {
coercedArgs.push({ value: origArgs[i]?.constructor?.name ?? typeof origArgs[i], tracked: false });
}
}
return {
args: coercedArgs,
tags: prefix ? utils.createAppendTags(null, strInfo.tags, prefix.length) : strInfo.tags,
};
}
function createAroundHook(entity, name, method, getInfoMethod, vulnerableArgIdxs) {

@@ -294,10 +337,4 @@ const argsIdxsToCheck = vulnerableArgIdxs || [0];

const { path, strInfo } = vulnInfo;
const objName = getObjectName(obj, entity);
const args = origArgs.map((arg, idx) => ({
value: isString(arg) ? arg : inspect(arg, { depth: 4 }),
tracked: idx === vulnArgIdx,
}));
const tags = path ? utils.createAdjustedQueryTags(path, strInfo.tags, strInfo.value, args[vulnArgIdx].value) : strInfo?.tags;
const { args, tags } = getAdjustedFields(origArgs, vulnInfo, vulnArgIdx);
const resultVal = args[args.length - 1].value.startsWith('[Function') ? '' : 'Promise';

@@ -307,3 +344,3 @@ const sinkEvent = createSinkEvent({

context: `${objName}.${method}(${args.map((a, idx) => isString(origArgs[idx]) ? `'${a.value}'` : a.value)})`,
history: [strInfo],
history: [vulnInfo.strInfo],
object: {

@@ -310,0 +347,0 @@ tracked: false,

@@ -19,2 +19,3 @@ /*

const { InputType } = require('@contrast/common');
const { InstrumentationType: { SOURCE } } = require('../../../constants');
const { patchType } = require('../common');

@@ -31,3 +32,9 @@

module.exports = function init(core) {
const { assess, depHooks, logger, patcher, scopes } = core;
const {
scopes,
assess: { dataflow, getSourceContext },
depHooks,
logger,
patcher,
} = core;

@@ -37,3 +44,3 @@ const preHook = (data) => {

data.args[2] = scopes.wrap(function contrastNext(...args) {
const sourceContext = scopes.sources.getStore()?.assess;
const sourceContext = getSourceContext(SOURCE);

@@ -74,3 +81,3 @@ if (!sourceContext) {

try {
assess.dataflow.sources.handle({
dataflow.sources.handle({
context,

@@ -96,3 +103,3 @@ data: _data,

assess.dataflow.sources.bodyParser1Instrumentation = {
core.assess.dataflow.sources.bodyParser1Instrumentation = {
install() {

@@ -135,3 +142,3 @@ depHooks.resolve(

return assess.dataflow.sources.bodyParser1Instrumentation;
return core.assess.dataflow.sources.bodyParser1Instrumentation;
};

@@ -19,6 +19,7 @@ /*

const { InputType } = require('@contrast/common');
const { InstrumentationType: { SOURCE } } = require('../../../constants');
const { patchType } = require('../common');
module.exports = function init(core) {
const { assess, depHooks, logger, patcher, scopes } = core;
const { assess, depHooks, logger, patcher } = core;

@@ -43,7 +44,7 @@ assess.dataflow.sources.cookieParser1Instrumentation = {

data.args[2] = function contrastNext(...args) {
const sourceContext = scopes.sources.getStore()?.assess;
const sourceContext = assess.getSourceContext(SOURCE);
if (!sourceContext) {
logger.error({ funcKey }, 'unable to handle source. Missing `sourceContext`');
return;
return next(...args);
}

@@ -50,0 +51,0 @@

@@ -18,7 +18,6 @@ /*

const { InputType } = require('@contrast/common');
const { InputType: { QUERYSTRING: inputType } } = require('@contrast/common');
const { patchType } = require('../common');
const { InstrumentationType: { SOURCE } } = require('../../../constants');
const inputType = InputType.QUERYSTRING;
module.exports = (core) => {

@@ -29,3 +28,6 @@ const {

logger,
assess: { dataflow: { sources } },
assess: {
getSourceContext,
dataflow: { sources }
},
} = core;

@@ -41,3 +43,3 @@

post({ args, hooked, orig, result, funcKey }) {
const sourceContext = core.scopes.sources.getStore()?.assess;
const sourceContext = getSourceContext(SOURCE);

@@ -44,0 +46,0 @@ if (!sourceContext) {

@@ -20,5 +20,11 @@ /*

const { patchType } = require('../common');
const { InstrumentationType: { SOURCE } } = require('../../../constants');
module.exports = (core) => {
const { depHooks, patcher, logger } = core;
const {
assess: { getSourceContext },
depHooks,
patcher,
logger,
} = core;

@@ -33,3 +39,3 @@ core.assess.dataflow.sources.querystringInstrumentation = {

post({ args, hooked, orig, result, funcKey }) {
const sourceContext = core.scopes.sources.getStore()?.assess;
const sourceContext = getSourceContext(SOURCE);
const inputType = InputType.QUERYSTRING;

@@ -36,0 +42,0 @@

@@ -17,2 +17,4 @@ /*

const { split } = require('@contrast/common');
//

@@ -465,4 +467,3 @@ // This module implements tag range manipulation functions. There are generally

}
return idx >= 0 ? createAppendTags([], tags, idx) : [...tags];
return idx >= 0 ? createAppendTags([], tags, idx) : { ...tags };
}

@@ -489,4 +490,4 @@

function createEscapeTagRanges(input, result, tags) {
const inputArr = input.split('');
const escapedArr = result.split('');
const inputArr = split(input, '');
const escapedArr = split(result, '');
const overlap = inputArr.filter((x) => {

@@ -493,0 +494,0 @@ if (escapedArr.includes(x)) {

@@ -42,3 +42,3 @@ /*

// policy will not exist if assess is altogether disabled for the active request e.g. url exclusion
if (!ctx || !ctx?.policy || instrumentation.isLocked()) return null;
if (!ctx?.policy || instrumentation.isLocked()) return null;

@@ -54,2 +54,3 @@ switch (type) {

}
case InstrumentationType.RULE: {

@@ -56,0 +57,0 @@ const [ruleId] = rest;

{
"name": "@contrast/assess",
"version": "1.27.2",
"version": "1.28.0",
"description": "Contrast service providing framework-agnostic Assess support",

@@ -20,3 +20,3 @@ "license": "SEE LICENSE IN LICENSE",

"dependencies": {
"@contrast/common": "1.20.1",
"@contrast/common": "1.21.0",
"@contrast/distringuish": "^4.4.0",

@@ -23,0 +23,0 @@ "@contrast/scopes": "1.4.1"

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