UNPKG

tslint-microsoft-contrib

Version:
196 lines 9.3 kB
"use strict"; var __extends = (this && this.__extends) || (function () { var extendStatics = function (d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; return extendStatics(d, b); } return function (d, b) { extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); var __makeTemplateObject = (this && this.__makeTemplateObject) || function (cooked, raw) { if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; } return cooked; }; Object.defineProperty(exports, "__esModule", { value: true }); var Lint = require("tslint"); var tsutils = require("tsutils"); var ts = require("typescript"); var AstUtils_1 = require("./utils/AstUtils"); var FORBIDDEN_IMPORT_FAILURE_STRING = 'Found child_process import'; var FOUND_EXEC_FAILURE_STRING = 'Found child_process.exec() with non-literal first argument'; var FORBIDDEN_MODULE_NAME = 'child_process'; var FORBIDDEN_FUNCTION_NAME = 'exec'; var Rule = (function (_super) { __extends(Rule, _super); function Rule() { return _super !== null && _super.apply(this, arguments) || this; } Rule.prototype.apply = function (sourceFile) { return this.applyWithFunction(sourceFile, walk); }; Rule.metadata = { ruleName: 'detect-child-process', type: 'maintainability', description: 'Detects instances of child_process and child_process.exec', rationale: Lint.Utils.dedent(templateObject_1 || (templateObject_1 = __makeTemplateObject(["\n It is dangerous to pass a string constructed at runtime as the first argument to the child_process.exec().\n <code>child_process.exec(cmd)</code> runs <code>cmd</code> as a shell command which allows attacker \n to execute malicious code injected into <code>cmd</code> string.\n Instead of <code>child_process.exec(cmd)</code> you should use <code>child_process.spawn(cmd)</code> \n or specify the command as a literal, e.g. <code>child_process.exec('ls')</code>.\n "], ["\n It is dangerous to pass a string constructed at runtime as the first argument to the child_process.exec().\n <code>child_process.exec(cmd)</code> runs <code>cmd</code> as a shell command which allows attacker \n to execute malicious code injected into <code>cmd</code> string.\n Instead of <code>child_process.exec(cmd)</code> you should use <code>child_process.spawn(cmd)</code> \n or specify the command as a literal, e.g. <code>child_process.exec('ls')</code>.\n "]))), options: null, optionsDescription: '', typescriptOnly: true, issueClass: 'SDL', issueType: 'Error', severity: 'Important', level: 'Opportunity for Excellence', group: 'Security', commonWeaknessEnumeration: '88' }; return Rule; }(Lint.Rules.AbstractRule)); exports.Rule = Rule; function getProhibitedImportedNames(namedImports) { return namedImports.elements .filter(function (x) { var originalIdentifier; if (x.propertyName === undefined) { originalIdentifier = x.name; } else { originalIdentifier = x.propertyName; } return tsutils.getIdentifierText(originalIdentifier) === FORBIDDEN_FUNCTION_NAME; }) .map(function (x) { return tsutils.getIdentifierText(x.name); }); } function isNotUndefined(value) { return value !== undefined; } function getProhibitedBoundNames(namedBindings) { return namedBindings.elements .filter(function (x) { if (!ts.isIdentifier(x.name)) { return false; } var importedName; if (x.propertyName === undefined) { importedName = tsutils.getIdentifierText(x.name); } else { if (ts.isIdentifier(x.propertyName)) { importedName = tsutils.getIdentifierText(x.propertyName); } else if (ts.isStringLiteral(x.propertyName)) { importedName = x.propertyName.text; } } return importedName === FORBIDDEN_FUNCTION_NAME; }) .map(function (x) { if (ts.isIdentifier(x.name)) { return tsutils.getIdentifierText(x.name); } return undefined; }) .filter(isNotUndefined); } function walk(ctx) { var childProcessModuleAliases = new Set(); var childProcessFunctionAliases = new Set(); function processImport(node, moduleAlias, importedFunctionsAliases, importedModuleName) { if (importedModuleName === FORBIDDEN_MODULE_NAME) { ctx.addFailureAt(node.getStart(), node.getWidth(), FORBIDDEN_IMPORT_FAILURE_STRING); if (moduleAlias !== undefined) { childProcessModuleAliases.add(moduleAlias); } importedFunctionsAliases.forEach(function (x) { return childProcessFunctionAliases.add(x); }); } } function processRequire(node) { var functionTarget = AstUtils_1.AstUtils.getFunctionTarget(node); if (functionTarget !== undefined || node.arguments.length === 0) { return; } var firstArg = node.arguments[0]; if (tsutils.isStringLiteral(firstArg) && firstArg.text === FORBIDDEN_MODULE_NAME) { var alias = void 0; var importedNames = []; if (tsutils.isVariableDeclaration(node.parent)) { if (tsutils.isIdentifier(node.parent.name)) { alias = tsutils.getIdentifierText(node.parent.name); } else if (tsutils.isObjectBindingPattern(node.parent.name)) { importedNames = getProhibitedBoundNames(node.parent.name); } } processImport(node, alias, importedNames, firstArg.text); } } function isProhibitedCall(node) { var functionName = AstUtils_1.AstUtils.getFunctionName(node); var functionTarget = AstUtils_1.AstUtils.getFunctionTarget(node); var hasNonStringLiteralFirstArgument = node.arguments.length > 0 && !tsutils.isStringLiteral(node.arguments[0]); if (functionTarget === undefined) { return childProcessFunctionAliases.has(functionName) && hasNonStringLiteralFirstArgument; } return (childProcessModuleAliases.has(functionTarget) && functionName === FORBIDDEN_FUNCTION_NAME && hasNonStringLiteralFirstArgument); } function processCallExpression(node) { var functionName = AstUtils_1.AstUtils.getFunctionName(node); if (functionName === 'require') { processRequire(node); } if (isProhibitedCall(node)) { ctx.addFailureAt(node.getStart(), node.getWidth(), FOUND_EXEC_FAILURE_STRING); } } function processImportDeclaration(node) { if (!tsutils.isStringLiteral(node.moduleSpecifier)) { return; } var moduleName = node.moduleSpecifier.text; var alias; var importedNames = []; if (node.importClause !== undefined) { if (node.importClause.name !== undefined) { alias = tsutils.getIdentifierText(node.importClause.name); } if (node.importClause.namedBindings !== undefined) { if (tsutils.isNamespaceImport(node.importClause.namedBindings)) { alias = tsutils.getIdentifierText(node.importClause.namedBindings.name); } else if (tsutils.isNamedImports(node.importClause.namedBindings)) { importedNames = getProhibitedImportedNames(node.importClause.namedBindings); } } } processImport(node, alias, importedNames, moduleName); } function processImportEqualsDeclaration(node) { if (tsutils.isExternalModuleReference(node.moduleReference)) { var moduleRef = node.moduleReference; if (tsutils.isStringLiteral(moduleRef.expression)) { var moduleName = moduleRef.expression.text; var alias = node.name.text; processImport(node, alias, [], moduleName); } } } function cb(node) { if (tsutils.isImportEqualsDeclaration(node)) { processImportEqualsDeclaration(node); } if (tsutils.isImportDeclaration(node)) { processImportDeclaration(node); } if (tsutils.isCallExpression(node)) { processCallExpression(node); } return ts.forEachChild(node, cb); } return ts.forEachChild(ctx.sourceFile, cb); } var templateObject_1; //# sourceMappingURL=detectChildProcessRule.js.map