@nodesecure/js-x-ray
Version:
JavaScript AST XRay analysis
84 lines • 2.77 kB
JavaScript
// Import Third-party Dependencies
import { getCallExpressionIdentifier } from "@nodesecure/estree-ast-utils";
// Import Internal Dependencies
import { generateWarning } from "../warnings.js";
import { rootLocation, toArrayLocation } from "../utils/toArrayLocation.js";
// CONSTANTS
const kSensitiveMethods = [
"os.userInfo",
"os.networkInterfaces",
"os.cpus",
"dns.getServers"
];
function validateNode(node, ctx) {
const tracer = ctx.sourceFile.tracer;
const id = getCallExpressionIdentifier(node);
if (id === null) {
return [false];
}
const data = tracer.getDataFromIdentifier(id);
if (data === null || 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);
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: { tracer } } = ctx;
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
});
}
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