UNPKG

@nodesecure/js-x-ray

Version:
99 lines 3.21 kB
// Import Internal Dependencies import { getCallExpressionIdentifier } from "../estree/index.js"; import { VariableTracer } from "../VariableTracer.js"; import { CALL_EXPRESSION_DATA } from "../contants.js"; import { rootLocation, toArrayLocation } from "../utils/toArrayLocation.js"; import { generateWarning } from "../warnings.js"; // CONSTANTS const kSensitiveModules = new Set(["os", "dns"]); const kSensitiveMethods = [ "os.userInfo", "os.networkInterfaces", "os.cpus", "dns.getServers" ]; function validateNode(node, ctx) { if (ctx.sourceFile.sensitivity === "aggressive") { return [false]; } if (ctx.context?.[CALL_EXPRESSION_DATA]?.identifierOrMemberExpr !== "JSON.stringify") { return [false]; } const castedNode = node; if (castedNode.arguments.length === 0) { return [false]; } return [true]; } function main(node, ctx) { const { sourceFile } = ctx; const firstArg = node.arguments[0]; if (firstArg.type !== "CallExpression") { return; } const id = getCallExpressionIdentifier(firstArg); if (!id) { return; } const data = sourceFile.tracer.getDataFromIdentifier(id); if (kSensitiveMethods.some((method) => data?.identifierOrMemberExpr === method && sourceFile.tracer.importedModules.has(method.split(".")[0]))) { const arrayLocation = ctx.context?.[data?.identifierOrMemberExpr]; if (arrayLocation) { arrayLocation.push(toArrayLocation(firstArg.loc ?? rootLocation())); } else { ctx.context[data?.identifierOrMemberExpr] = [toArrayLocation(firstArg.loc ?? rootLocation())]; } } } function initialize(ctx) { const { sourceFile, context } = ctx; const { tracer } = sourceFile; tracer .trace("JSON.stringify", { followConsecutiveAssignment: true }) .trace("os.userInfo", { moduleName: "os", followConsecutiveAssignment: true }) .trace("os.networkInterfaces", { moduleName: "os", followConsecutiveAssignment: true }) .trace("os.cpus", { moduleName: "os", followConsecutiveAssignment: true }) .trace("dns.getServers", { moduleName: "dns", followConsecutiveAssignment: true }); if (sourceFile.sensitivity !== "aggressive") { return; } tracer.on(VariableTracer.ImportEvent, ({ moduleName, location }) => { if (kSensitiveModules.has(moduleName) && !(moduleName in context)) { context[moduleName] = [toArrayLocation(location ?? undefined)]; } }); } function finalize(ctx) { const { sourceFile, context } = ctx; if (context && Object.keys(context).length > 0) { const warning = generateWarning("data-exfiltration", { value: Object.keys(context).join(", ") }); sourceFile.warnings.push({ ...warning, location: Object.values(context).flat() }); } } const dateExifiltration = { name: "dataExfiltration", validateNode, initialize, finalize, main, breakOnMatch: false, context: {} }; export default dateExifiltration; //# sourceMappingURL=data-exfiltration.js.map