@nodesecure/js-x-ray
Version:
JavaScript AST XRay analysis
68 lines • 2.07 kB
JavaScript
// Import Third-party Dependencies
import { getCallExpressionIdentifier, getMemberExpressionIdentifier } from "@nodesecure/estree-ast-utils";
// Import Internal Dependencies
import { generateWarning } from "../warnings.js";
/**
* @description Detect serialization of process.env which could indicate environment variable exfiltration
* @example
* JSON.stringify(process.env)
* JSON.stringify(process["env"])
* JSON.stringify(process["env"])
* JSON.stringify(process[`env`])
*/
function validateNode(node, ctx) {
const { tracer } = ctx.sourceFile;
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];
}
const firstArg = castedNode.arguments[0];
if (firstArg.type === "MemberExpression") {
const memberExprId = [...getMemberExpressionIdentifier(firstArg)].join(".");
if (memberExprId === "process.env") {
return [true];
}
}
if (firstArg.type === "Identifier") {
const data = tracer.getDataFromIdentifier(firstArg.name);
if (data !== null) {
return [true];
}
}
return [false];
}
function main(node, ctx) {
const { sourceFile, signals } = ctx;
const warning = generateWarning("serialize-environment", {
value: "JSON.stringify(process.env)",
location: node.loc
});
sourceFile.warnings.push(warning);
return signals.Skip;
}
function initialize(ctx) {
const { tracer } = ctx.sourceFile;
tracer
.trace("process.env", {
followConsecutiveAssignment: true
})
.trace("JSON.stringify", {
followConsecutiveAssignment: true
});
}
export default {
name: "isSerializeEnv",
validateNode,
initialize,
main,
breakOnMatch: false
};
//# sourceMappingURL=isSerializeEnv.js.map