Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
122 changes: 61 additions & 61 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,61 +1,61 @@
{
"name": "@nodesecure/js-x-ray",
"version": "6.1.1",
"description": "JavaScript AST XRay analysis",
"type": "module",
"exports": "./index.js",
"engines": {
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
},
"scripts": {
"lint": "eslint src test",
"prepublishOnly": "pkg-ok",
"test-only": "cross-env esm-tape-runner 'test/**/*.spec.js' | tap-monkey",
"test": "c8 --all --src ./src --reporter=lcov npm run test-only",
"check": "cross-env npm run lint && npm run test-only"
},
"repository": {
"type": "git",
"url": "git+https://github.com/NodeSecure/js-x-ray.git"
},
"keywords": [
"ast",
"nsecure",
"nodesecure",
"analysis",
"dependencies",
"security"
],
"files": [
"src",
"types",
"index.js",
"index.d.ts"
],
"author": "GENTILHOMME Thomas <[email protected]>",
"license": "MIT",
"bugs": {
"url": "https://github.com/NodeSecure/js-x-ray/issues"
},
"homepage": "https://github.com/NodeSecure/js-x-ray#readme",
"dependencies": {
"@nodesecure/estree-ast-utils": "^1.3.1",
"@nodesecure/sec-literal": "^1.2.0",
"estree-walker": "^3.0.1",
"is-minified-code": "^2.0.0",
"meriyah": "^4.3.3",
"safe-regex": "^2.1.1"
},
"devDependencies": {
"@nodesecure/eslint-config": "^1.6.0",
"@slimio/is": "^2.0.0",
"@small-tech/esm-tape-runner": "^2.0.0",
"@small-tech/tap-monkey": "^1.4.0",
"@types/node": "^20.3.0",
"c8": "^8.0.0",
"cross-env": "^7.0.3",
"eslint": "^8.31.0",
"pkg-ok": "^3.0.0",
"tape": "^5.6.1"
}
}
{
"name": "@nodesecure/js-x-ray",
"version": "6.1.1",
"description": "JavaScript AST XRay analysis",
"type": "module",
"exports": "./index.js",
"engines": {
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
},
"scripts": {
"lint": "eslint src test",
"prepublishOnly": "pkg-ok",
"test-only": "cross-env esm-tape-runner 'test/**/*.spec.js' | tap-monkey",
"test": "c8 --all --src ./src --reporter=lcov npm run test-only",
"check": "cross-env npm run lint && npm run test-only"
},
"repository": {
"type": "git",
"url": "git+https://github.com/NodeSecure/js-x-ray.git"
},
"keywords": [
"ast",
"nsecure",
"nodesecure",
"analysis",
"dependencies",
"security"
],
"files": [
"src",
"types",
"index.js",
"index.d.ts"
],
"author": "GENTILHOMME Thomas <[email protected]>",
"license": "MIT",
"bugs": {
"url": "https://github.com/NodeSecure/js-x-ray/issues"
},
"homepage": "https://github.com/NodeSecure/js-x-ray#readme",
"dependencies": {
"@nodesecure/estree-ast-utils": "^1.4.1",
"@nodesecure/sec-literal": "^1.2.0",
"estree-walker": "^3.0.1",
"is-minified-code": "^2.0.0",
"meriyah": "^4.3.3",
"safe-regex": "^2.1.1"
},
"devDependencies": {
"@nodesecure/eslint-config": "^1.6.0",
"@slimio/is": "^2.0.0",
"@small-tech/esm-tape-runner": "^2.0.0",
"@small-tech/tap-monkey": "^1.4.0",
"@types/node": "^20.3.0",
"c8": "^8.0.0",
"cross-env": "^7.0.3",
"eslint": "^8.31.0",
"pkg-ok": "^3.0.0",
"tape": "^5.6.1"
}
}
20 changes: 16 additions & 4 deletions src/probes/isRequire.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ import {
concatBinaryExpression,
arrayExpressionToString,
getMemberExpressionIdentifier,
getCallExpressionIdentifier
getCallExpressionIdentifier,
getCallExpressionArguments
} from "@nodesecure/estree-ast-utils";

function validateNode(node, { tracer }) {
Expand Down Expand Up @@ -89,7 +90,7 @@ function main(node, options) {

// require(Buffer.from("...", "hex").toString());
case "CallExpression": {
walkRequireCallExpression(arg)
walkRequireCallExpression(arg, tracer)
.forEach((depName) => analysis.dependencies.add(depName, node.loc, true));

analysis.addWarning("unsafe-import", null, node.loc);
Expand All @@ -103,7 +104,7 @@ function main(node, options) {
}
}

function walkRequireCallExpression(nodeToWalk) {
function walkRequireCallExpression(nodeToWalk, tracer) {
const dependencies = new Set();

walk(nodeToWalk, {
Expand All @@ -122,8 +123,19 @@ function walkRequireCallExpression(nodeToWalk) {
const fullName = node.callee.type === "MemberExpression" ?
[...getMemberExpressionIdentifier(node.callee)].join(".") :
node.callee.name;
const tracedFullName = tracer.getDataFromIdentifier(fullName)?.name ?? fullName;

switch (tracedFullName) {
case "atob": {
const nodeArguments = getCallExpressionArguments(node, { tracer });
if (nodeArguments !== null) {
dependencies.add(
Buffer.from(nodeArguments.at(0), "base64").toString()
);
}

switch (fullName) {
break;
}
case "Buffer.from": {
const [element] = node.arguments;

Expand Down
20 changes: 20 additions & 0 deletions test/probes/isRequire.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -395,3 +395,23 @@ test("(require CallExpression): it should detect MemberExpression require.resolv

tape.end();
});

test("(require CallExpression): it should detect obfuscated atob value", (tape) => {
const str = `
const myFunc = atob;
const ff = myFunc('b3' + 'M=');
const dep = require(ff);
`;
const ast = parseScript(str);
const sastAnalysis = getSastAnalysis(str, isRequire)
.execute(ast.body);

tape.strictEqual(sastAnalysis.warnings().length, 0);

const dependencies = sastAnalysis.dependencies();
tape.strictEqual(Object.keys(dependencies).length, 1);
tape.ok("os" in dependencies);

tape.end();
});