Skip to content

Commit 49c5bbb

Browse files
authored
refactor(typo-squatting): remove on local scan or when similar >= 3 (#542)
1 parent 5765023 commit 49c5bbb

File tree

6 files changed

+60
-22
lines changed

6 files changed

+60
-22
lines changed

.changeset/large-emus-taste.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@nodesecure/scanner": minor
3+
---
4+
5+
Improve type-squatting global-warning by removing it on remote scan and also when there is to much similar packages

workspaces/scanner/src/depWalker.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,8 @@ export async function depWalker(
289289
try {
290290
const { warnings, illuminated } = await getDependenciesWarnings(
291291
dependencies,
292-
options.highlight?.contacts
292+
options.highlight?.contacts,
293+
typeof location === "undefined"
293294
);
294295
payload.warnings = globalWarnings.concat(dependencyConfusionWarnings as GlobalWarning[]).concat(warnings);
295296
payload.highlighted = {

workspaces/scanner/src/i18n/english.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { taggedString as tS } from "@nodesecure/i18n";
44
const scanner = {
55
disable_scarf: "This dependency could collect data against your consent so think to disable it with the env var: SCARF_ANALYTICS",
66
keylogging: "This dependency can retrieve your keyboard and mouse inputs. It can be used for 'keylogging' attacks/malwares.",
7-
typo_squatting: tS`The package '${0}' is similar to the following popular packages: ${1}`,
7+
typo_squatting: tS`Dependency '${0}' is similar to the following popular packages: ${1}`,
88
dependency_confusion: "This dependency was found on both a public and private registry but its signature does not match",
99
dependency_confusion_missing: "This dependency was found on the private but not on the public registry, this dependency is vulnerable to dependency confusion attacks.",
1010
dependency_confusion_missing_org: tS`The org '${0}' is not claimed on the public registry`

workspaces/scanner/src/i18n/french.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { taggedString as tS } from "@nodesecure/i18n";
44
const scanner = {
55
disable_scarf: "Cette dépendance peut récolter des données contre votre volonté, pensez donc à la désactiver en fournissant la variable d'environnement SCARF_ANALYTICS",
66
keylogging: "Cette dépendance peut obtenir vos entrées clavier ou de souris. Cette dépendance peut être utilisée en tant que 'keylogging' attacks/malwares.",
7-
typo_squatting: tS`Le package '${0}' est similaire aux packages populaires suivants : ${1}`,
7+
typo_squatting: tS`La dépendance '${0}' est similaire aux packages populaires suivants : ${1}`,
88
dependency_confusion: "Cette dépendance a été trouvée à la fois sur un registre public et privé, mais sa signature ne correspond pas.",
99
dependency_confusion_missing: "Cette dépendance a été trouvée seulement sur le registre privé, cette dépendance est vulnérable à une attaque par confusion de dépendance.",
1010
dependency_confusion_missing_org: tS`L'organisation '${0}' n'est pas revendiquée sur le registre public`

workspaces/scanner/src/utils/warnings.ts

Lines changed: 37 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@ export interface GetWarningsResult {
4141

4242
export async function getDependenciesWarnings(
4343
dependenciesMap: Map<string, Dependency>,
44-
highlightContacts: Contact[] = []
44+
highlightContacts: Contact[] = [],
45+
isLocalScan = false
4546
): Promise<GetWarningsResult> {
4647
const vulnerableDependencyNames = Object.keys(
4748
kDependencyWarnMessage
@@ -64,21 +65,14 @@ export async function getDependenciesWarnings(
6465
const dependencies: Record<string, ContactExtractorPackageMetadata> = Object.create(null);
6566
for (const [packageName, dependency] of dependenciesMap) {
6667
const { author, maintainers } = dependency.metadata;
67-
const similarPackages = topPackages.getSimilarPackages(packageName);
68-
if (similarPackages.length > 0) {
69-
const warningMessage = await i18n.getToken(
70-
"scanner.typo_squatting",
71-
packageName,
72-
similarPackages.join(", ")
73-
);
74-
warnings.push({
75-
type: "typo-squatting",
76-
message: warningMessage,
77-
metadata: {
78-
name: packageName,
79-
similar: similarPackages
80-
}
81-
});
68+
69+
const warning = await (
70+
isLocalScan ?
71+
Promise.resolve(null) :
72+
searchTypoSquattingByName(topPackages, packageName)
73+
);
74+
if (warning !== null) {
75+
warnings.push(warning);
8276
}
8377

8478
dependencies[packageName] = {
@@ -107,3 +101,30 @@ export async function getDependenciesWarnings(
107101
};
108102
}
109103

104+
async function searchTypoSquattingByName(
105+
topPackages: TopPackages,
106+
packageName: string
107+
): Promise<GlobalWarning | null> {
108+
const similarPackages = topPackages.getSimilarPackages(packageName);
109+
if (
110+
similarPackages.length > 0 &&
111+
similarPackages.length <= 3
112+
) {
113+
const warningMessage = await i18n.getToken(
114+
"scanner.typo_squatting",
115+
packageName,
116+
similarPackages.join(", ")
117+
);
118+
119+
return {
120+
type: "typo-squatting",
121+
message: warningMessage,
122+
metadata: {
123+
name: packageName,
124+
similar: similarPackages
125+
}
126+
};
127+
}
128+
129+
return null;
130+
}

workspaces/scanner/test/depWalker.spec.ts

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -132,11 +132,12 @@ test("execute depWalker on pkg.gitdeps", async() => {
132132
].sort());
133133
});
134134

135-
test("execute depWalker on typo-squatting", async() => {
135+
test("execute depWalker on typo-squatting (with location)", async() => {
136136
Vulnera.setStrategy(Vulnera.strategies.GITHUB_ADVISORY);
137137

138138
const result = await depWalker(pkgTypoSquatting, {
139-
registry: getLocalRegistryURL()
139+
registry: getLocalRegistryURL(),
140+
location: ""
140141
});
141142

142143
assert.ok(result.warnings.length > 0);
@@ -145,10 +146,20 @@ test("execute depWalker on typo-squatting", async() => {
145146
assert.equal(warning.type, "typo-squatting");
146147
assert.strictEqual(
147148
result.warnings[0].message,
148-
"The package 'mecha' is similar to the following popular packages: fecha, mocha"
149+
"Dependency 'mecha' is similar to the following popular packages: fecha, mocha"
149150
);
150151
});
151152

153+
test("execute depWalker on typo-squatting (with no location)", async() => {
154+
Vulnera.setStrategy(Vulnera.strategies.GITHUB_ADVISORY);
155+
156+
const result = await depWalker(pkgTypoSquatting, {
157+
registry: getLocalRegistryURL()
158+
});
159+
160+
assert.ok(result.warnings.length === 0);
161+
});
162+
152163
test("fetch payload of pacote on the npm registry", async() => {
153164
const result = await from("pacote", {
154165
maxDepth: 10,

0 commit comments

Comments
 (0)