Skip to content

Commit

Permalink
Add JS injection tests
Browse files Browse the repository at this point in the history
  • Loading branch information
timokoessler committed Dec 13, 2024
1 parent 3f3ff97 commit aeec6fd
Show file tree
Hide file tree
Showing 3 changed files with 144 additions and 5 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import * as t from "tap";
import { checkContextForJsInjection } from "./checkContextForJsInjection";

t.test("it returns correct path", async () => {
t.same(
checkContextForJsInjection({
js: "const x = 1 + 1; fetch();",
operation: "eval",
context: {
cookies: {},
headers: {},
remoteAddress: "ip",
method: "POST",
url: "url",
query: {},
body: {
calc: "1 + 1; fetch()",
},
source: "express",
route: "/",
routeParams: {},
},
}),
{
operation: "eval",
kind: "js_injection",
source: "body",
pathToPayload: ".calc",
metadata: {
js: "const x = 1 + 1; fetch();",
},
payload: "1 + 1; fetch()",
}
);
});
92 changes: 92 additions & 0 deletions library/vulnerabilities/js-injection/detectJsInjection.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import * as t from "tap";
import { detectJsInjection } from "./detectJsInjection";

t.test("it detects JS injections", async (t) => {
t.same(
detectJsInjection(
'1 + 1; console.log("hello")',
'1 + 1; console.log("hello")'
),
true
);
t.same(detectJsInjection("const x = 1 + 1; fetch();", "+ 1; fetch()"), true);
t.same(
detectJsInjection("const test = 'Hello World!'; //';", "Hello World!'; //"),
true
);
t.same(
detectJsInjection(
"if (username === 'admin' || 1 === 1) { return true; } //') {}",
"admin' || 1 === 1) { return true; } //"
),
true
);
t.same(
detectJsInjection(
"packet.readDateTimeString('abc'); process.exit(1); // ');",
"abc'); process.exit(1); //"
),
true
);
t.same(
detectJsInjection(
"const window={}; alert('!'); return window.__NUXT__",
"alert('!');"
),
true
);
t.same(
detectJsInjection(
"const obj = { test: 'value', isAdmin: true }; //'};",
"value', isAdmin: true }; //"
),
true
);
});

t.test("does not detect JS injections", async (t) => {
t.same(detectJsInjection("1 + 1", "1 + 1"), false);
t.same(detectJsInjection("1 + 1", "const x = 1 + 1; x"), false);
t.same(detectJsInjection("1 + 1", "1 + 1; console.log('hello')"), false);
t.same(detectJsInjection("1 + 1", "1"), false);
t.same(detectJsInjection("1 + 1", "abc"), false);
t.same(detectJsInjection("const x = 'test'", "test"), false);
t.same(detectJsInjection("const x = 'test'", ""), false);
t.same(detectJsInjection("const test = 'abcde_123';", "abcde_123"), false);
t.same(detectJsInjection("const test = [1, 2, 3];", "1, 2, 3"), false);

t.same(
detectJsInjection("const test = 'Hello World!';", "Hello World!"),
false
);
t.same(
detectJsInjection(
"if(username === 'admin' || 1 === 1) { return true; }",
"admin"
),
false
);
t.same(
detectJsInjection("const obj = { test: 'value', isAdmin: true };", "value"),
false
);
});

t.test("test source type", async (t) => {
t.same(
detectJsInjection(
"const test: string = 'Hello World!'; console.log('test'); //';",
"Hello World!'; console.log('test'); //",
0
),
false // Cannot be parsed as JS, it's TS
);
t.same(
detectJsInjection(
"const test: string = 'Hello World!'; console.log('test'); //';",
"Hello World!'; console.log('test'); //",
1
),
true
);
});
22 changes: 17 additions & 5 deletions library/vulnerabilities/js-injection/detectJsInjection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,26 @@ import { shouldReturnEarly } from "./shouldReturnEarly";
// eslint-disable-next-line camelcase
import { wasm_detect_js_injection } from "../../internals/zen_internals";

export function detectJsInjection(query: string, userInput: string) {
const queryLowercase = query.toLowerCase();
/**
* Detects if the user input is a JS injection
* The sourceType is used to determine the source of the user input
* https://github.com/AikidoSec/zen-internals/blob/4b7bf2c7796155731dc2736a04e3f4d99cdc712b/src/js_injection/helpers/select_sourcetype_based_on_enum.rs#L4
*/
export function detectJsInjection(
code: string,
userInput: string,
sourceType = 0
): boolean {
const codeLowercase = code.toLowerCase();
const userInputLowercase = userInput.toLowerCase();

if (shouldReturnEarly(queryLowercase, userInputLowercase)) {
if (shouldReturnEarly(codeLowercase, userInputLowercase)) {
return false;
}

// The source type is currently hardcoded to 0 (CJS & ESM)
return wasm_detect_js_injection(queryLowercase, userInputLowercase, 0);
return wasm_detect_js_injection(
codeLowercase,
userInputLowercase,
sourceType
);
}

0 comments on commit aeec6fd

Please sign in to comment.