UNPKG

@hclsoftware/secagent

Version:

IAST agent

85 lines (78 loc) 4.21 kB
//IASTIGNORE /* * **************************************************** * Licensed Materials - Property of HCL. * (c) Copyright HCL Technologies Ltd. 2017, 2025. * Note to U.S. Government Users *Restricted Rights. * **************************************************** */ const HookRule = require('./HookRule') const TaintTracker = require('../../TaintTracker') const StackInfo = require("../../StackInfo"); const {EntityType} = require("../../Entity"); /** * Used to propagate taint from object to the string or a String or a Buffer target object or Object's properties. * * Note: * 1. If the target is one of the arguments, and it's a value type string then the taint propagation * to that argument will NOT have any effect on the actual argument in the user code. * 2. And if the target is Reference type then the taint propagation to that argument will still hold the taint in the user code. * 3. If target is the result or the returned, and if is a value type string we wrap it with a String Object and return the target. * then it would still hold taint in the user's code. * @class PropagatorRule * @extends HookRule * @see HookRule */ class PropagatorRule extends HookRule { doHook (hookValues) { const source = HookRule.getActualParam(this.data.from, hookValues, this.data.optional) const parameters = StackInfo.getParamsStringArray(hookValues.that, hookValues.simpleThat, hookValues.methodName, hookValues.args, hookValues.simpleRet) if (TaintTracker.isObjectTainted(source)){ // if target was a string then we need to wrap it with a String object and set hookValues.ret if (this.data.to === HookRule.constantArgs.RETURN) { // eslint-disable-next-line no-new-wrappers hookValues.ret = typeof hookValues.ret === 'string' ? new String(hookValues.ret) : hookValues.ret } let target = HookRule.getActualParam(this.data.to, hookValues); if (target == null) return // if target is null then we don't need to propagate taint if (target instanceof String || Buffer.isBuffer(target)) { if(source instanceof String || Buffer.isBuffer(source)){ TaintTracker.propagateTaint(source, target, hookValues.simpleThat, hookValues.methodName, hookValues.args, hookValues.simpleRet) } else if (typeof source === 'object') { TaintTracker.propagateTaintFromObject(source, target, hookValues.simpleThat, hookValues.methodName, hookValues.args, hookValues.simpleRet) } } else if (typeof target === 'object') { this.propagateTaintToObject(source, target, parameters) } else { throw new Error(`PropagatorRule: Target is not a String or a Buffer or an Object: Current Type ${typeof target} and target = ${target}. Consider using other Propagator rules`) } } } /** * Propagate taint from source to object by recursively traversing the object properties. * 1. if source is object we iterate over the properties of the source and recursively call this function. * 2. if the source is a string we propagate taint to the object properties */ propagateTaintToObject(source, obj, parameters, entityName, memoization) { memoization = memoization || new Set() if (memoization.has(obj)) return obj memoization.add(obj) if (typeof obj === 'string') { // could be either string or tainted data if (obj !== Object(obj)) { obj = new String(obj) } let newTaintedObject = TaintTracker.propagateTaintWithParameters(source, obj, parameters); if (entityName !== null) { newTaintedObject.updateEntity(entityName, obj.origToString(), EntityType.PARAMETER) } } else { for (const property in obj) { if (Object.prototype.hasOwnProperty.call(obj, property) && obj[property] != null) { obj[property] = this.propagateTaintToObject(source, obj[property], parameters, property, memoization) } } } return obj } } module.exports = PropagatorRule