UNPKG

@nodesecure/js-x-ray

Version:
97 lines 2.94 kB
// Import Internal Dependencies import { getMemberExpressionIdentifier } from "../estree/index.js"; import { CALL_EXPRESSION_DATA } from "../contants.js"; 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 validateJsonStringify(node, ctx) { const { tracer } = ctx.sourceFile; if (ctx.context[CALL_EXPRESSION_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]; } /** * @description Detect direct process.env access (for aggressive mode) * @example * process.env * const env = process.env */ function validateProcessEnv(node, ctx) { if (node.type !== "MemberExpression") { return [false]; } const memberExprId = [...getMemberExpressionIdentifier(node)].join("."); if (memberExprId === "process.env") { ctx.setEntryPoint("process.env"); return [true]; } return [false]; } function defaultHandler(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 processEnvHandler(node, ctx) { const { sourceFile, signals } = ctx; // Only trigger warning in aggressive mode if (sourceFile.sensitivity !== "aggressive") { return null; } const warning = generateWarning("serialize-environment", { value: "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: [validateJsonStringify, validateProcessEnv], initialize, main: { default: defaultHandler, "process.env": processEnvHandler }, breakOnMatch: false, context: {} }; //# sourceMappingURL=isSerializeEnv.js.map