From 0c8a0984da4194e2518eb60a8052ed340c93bcd3 Mon Sep 17 00:00:00 2001 From: PierreDemailly Date: Thu, 9 Mar 2023 21:56:20 +0100 Subject: [PATCH 1/3] feat: add shady-link warning --- README.md | 4 +++- docs/shady-link.md | 16 ++++++++++++++++ src/probes/isLiteral.js | 3 +++ src/warnings.js | 5 +++++ test/probes/isLiteral.spec.js | 12 ++++++++++++ types/warnings.d.ts | 3 ++- 6 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 docs/shady-link.md diff --git a/README.md b/README.md index b7bf6ea7..1102886c 100644 --- a/README.md +++ b/README.md @@ -101,7 +101,8 @@ type WarningName = "parsing-error" | "suspicious-file" | "obfuscated-code" | "weak-crypto" -| "unsafe-import"; +| "unsafe-import" +| "shady-link"; declare const warnings: Record **Note** credit goes to the [guarddog](https://github.dev/DataDog/guarddog) team. + +## Example + +```js +const foo = "http://foo.xyz"; +``` diff --git a/src/probes/isLiteral.js b/src/probes/isLiteral.js index 9c48349a..c779ec36 100644 --- a/src/probes/isLiteral.js +++ b/src/probes/isLiteral.js @@ -37,6 +37,9 @@ function main(node, options) { analysis.addWarning("encoded-literal", node.value, node.loc); } } + else if (/(http[s]?:\/\/.*\.(link|xyz|tk|ml|ga|cf|gq|pw|top|club|mw|bd|ke|am|sbs|date|quest|cd|bid|cd|ws|icu|cam|uno|email|stream))$/.test(node.value)) { + analysis.addWarning("shady-link", node.value, node.loc); + } // Else we are checking all other string with our suspect method else { analysis.analyzeLiteral(node); diff --git a/src/warnings.js b/src/warnings.js index 21dbd99c..5f672ff9 100644 --- a/src/warnings.js +++ b/src/warnings.js @@ -45,6 +45,11 @@ export const warnings = Object.freeze({ i18n: "sast_warnings.weak_crypto", severity: "Information", experimental: true + }, + "shady-link": { + i18n: "sast_warnings.shady_link", + severity: "Warning", + experimental: true } }); diff --git a/test/probes/isLiteral.spec.js b/test/probes/isLiteral.spec.js index c2850a86..87409323 100644 --- a/test/probes/isLiteral.spec.js +++ b/test/probes/isLiteral.spec.js @@ -86,3 +86,15 @@ test("should not throw any warnings without hexadecimal value (and should call a tape.end(); }); + +test("should detect shady link", (tape) => { + const str = "const foo = 'http://foobar.link'"; + const ast = parseScript(str); + const sastAnalysis = getSastAnalysis(str, isLiteral).execute(ast.body); + + tape.strictEqual(sastAnalysis.warnings().length, 1); + const warning = sastAnalysis.getWarning("shady-link"); + tape.strictEqual(warning.value, "http://foobar.link"); + + tape.end(); +}); diff --git a/types/warnings.d.ts b/types/warnings.d.ts index 5b7b9cb8..5185a444 100644 --- a/types/warnings.d.ts +++ b/types/warnings.d.ts @@ -15,7 +15,8 @@ type WarningNameWithValue = "parsing-error" | "suspicious-literal" | "suspicious-file" | "obfuscated-code" -| "weak-crypto"; +| "weak-crypto" +| "shady-link"; type WarningName = WarningNameWithValue | "unsafe-import"; type WarningLocation = [[number, number], [number, number]]; From 2daa3b4791ad2bc6f007aee696ba0bd04ee4ce55 Mon Sep 17 00:00:00 2001 From: PierreDemailly Date: Fri, 10 Mar 2023 11:54:52 +0100 Subject: [PATCH 2/3] feat: detect bit.ly shady links --- src/probes/isLiteral.js | 15 ++++++++++++--- test/probes/isLiteral.spec.js | 15 ++++++++++++++- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/src/probes/isLiteral.js b/src/probes/isLiteral.js index c779ec36..9a8388d5 100644 --- a/src/probes/isLiteral.js +++ b/src/probes/isLiteral.js @@ -6,6 +6,10 @@ import { Hex } from "@nodesecure/sec-literal"; // CONSTANTS const kNodeDeps = new Set(builtinModules); +const kShadyLinkRegExps = [ + /(http[s]?:\/\/bit\.ly.*)$/, + /(http[s]?:\/\/.*\.(link|xyz|tk|ml|ga|cf|gq|pw|top|club|mw|bd|ke|am|sbs|date|quest|cd|bid|cd|ws|icu|cam|uno|email|stream))$/ +]; /** * @description Search for Literal AST Node @@ -37,11 +41,16 @@ function main(node, options) { analysis.addWarning("encoded-literal", node.value, node.loc); } } - else if (/(http[s]?:\/\/.*\.(link|xyz|tk|ml|ga|cf|gq|pw|top|club|mw|bd|ke|am|sbs|date|quest|cd|bid|cd|ws|icu|cam|uno|email|stream))$/.test(node.value)) { - analysis.addWarning("shady-link", node.value, node.loc); - } // Else we are checking all other string with our suspect method else { + for (const regex of kShadyLinkRegExps) { + if (regex.test(node.value)) { + analysis.addWarning("shady-link", node.value, node.loc); + + return; + } + } + analysis.analyzeLiteral(node); } } diff --git a/test/probes/isLiteral.spec.js b/test/probes/isLiteral.spec.js index 87409323..79b1925d 100644 --- a/test/probes/isLiteral.spec.js +++ b/test/probes/isLiteral.spec.js @@ -87,7 +87,7 @@ test("should not throw any warnings without hexadecimal value (and should call a tape.end(); }); -test("should detect shady link", (tape) => { +test("should detect shady link when an URL is bit.ly", (tape) => { const str = "const foo = 'http://foobar.link'"; const ast = parseScript(str); const sastAnalysis = getSastAnalysis(str, isLiteral).execute(ast.body); @@ -98,3 +98,16 @@ test("should detect shady link", (tape) => { tape.end(); }); + + +test("should detect shady link when an URL has a suspicious domain", (tape) => { + const str = "const foo = 'http://bit.ly/foo'"; + const ast = parseScript(str); + const sastAnalysis = getSastAnalysis(str, isLiteral).execute(ast.body); + + tape.strictEqual(sastAnalysis.warnings().length, 1); + const warning = sastAnalysis.getWarning("shady-link"); + tape.strictEqual(warning.value, "http://bit.ly/foo"); + + tape.end(); +}); From b6103e9fa7df81877d9ec080759da915987d2f7c Mon Sep 17 00:00:00 2001 From: PierreDemailly Date: Fri, 10 Mar 2023 11:57:48 +0100 Subject: [PATCH 3/3] styles: rename tests --- test/probes/isLiteral.spec.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/probes/isLiteral.spec.js b/test/probes/isLiteral.spec.js index 79b1925d..ca7ab2ad 100644 --- a/test/probes/isLiteral.spec.js +++ b/test/probes/isLiteral.spec.js @@ -88,26 +88,26 @@ test("should not throw any warnings without hexadecimal value (and should call a }); test("should detect shady link when an URL is bit.ly", (tape) => { - const str = "const foo = 'http://foobar.link'"; + const str = "const foo = 'http://bit.ly/foo'"; const ast = parseScript(str); const sastAnalysis = getSastAnalysis(str, isLiteral).execute(ast.body); tape.strictEqual(sastAnalysis.warnings().length, 1); const warning = sastAnalysis.getWarning("shady-link"); - tape.strictEqual(warning.value, "http://foobar.link"); + tape.strictEqual(warning.value, "http://bit.ly/foo"); tape.end(); }); test("should detect shady link when an URL has a suspicious domain", (tape) => { - const str = "const foo = 'http://bit.ly/foo'"; + const str = "const foo = 'http://foobar.link'"; const ast = parseScript(str); const sastAnalysis = getSastAnalysis(str, isLiteral).execute(ast.body); tape.strictEqual(sastAnalysis.warnings().length, 1); const warning = sastAnalysis.getWarning("shady-link"); - tape.strictEqual(warning.value, "http://bit.ly/foo"); + tape.strictEqual(warning.value, "http://foobar.link"); tape.end(); });