Skip to content

Commit 519d79f

Browse files
committed
Harden Chrome extension: disable runtime extractor execution
1 parent bab5ae5 commit 519d79f

File tree

2 files changed

+33
-45
lines changed

2 files changed

+33
-45
lines changed

chrome/extension/background.html

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
44
</head>
55
<body>
6-
<iframe id="sandboxframe" src="sandbox.html"></iframe>
7-
86
<script src="js/sha1.js"></script>
97
<script src="js/events.js"></script>
108
<script src="js/generated/retire-chrome.js" charset="utf-8"></script>

chrome/extension/js/background.js

Lines changed: 33 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,12 @@ const repoUrl =
44
"https://raw.githubusercontent.com/RetireJS/retire.js/master/repository/jsrepository-v5.json";
55
let updatedAt = Date.now();
66
let repo;
7-
let backdoorData;
8-
let repoFuncs;
7+
let backdoorData = {};
98

109
const retire = retirechrome.retire;
1110

1211
let vulnerable = {};
1312
const events = new Emitter();
14-
let sandboxWin;
1513

1614
const hasher = {
1715
sha1: function (data) {
@@ -44,22 +42,40 @@ async function downloadRepo() {
4442
);
4543
}
4644
const parsedRepo = JSON.parse(retire.replaceVersion(repoData));
47-
repo = parsedRepo.advisories;
48-
backdoorData = parsedRepo.backdoored;
45+
// jsrepository-v5.json is a flat advisory map. Keep backward compatibility
46+
// if a wrapped format with `advisories`/`backdoored` is provided.
47+
if (parsedRepo && parsedRepo.advisories) {
48+
repo = sanitizeRepo(parsedRepo.advisories);
49+
backdoorData = parsedRepo.backdoored || {};
50+
} else {
51+
repo = sanitizeRepo(parsedRepo);
52+
backdoorData = {};
53+
}
4954
console.log(repo);
5055
console.log(backdoorData);
5156
console.log("Done");
5257
vulnerable = {};
53-
setFuncs();
5458
}
5559

56-
function setFuncs() {
57-
repoFuncs = {};
58-
for (var component in repo) {
59-
if (repo[component].extractors.func) {
60-
repoFuncs[component] = repo[component].extractors.func;
61-
}
60+
function sanitizeRepo(inputRepo) {
61+
// Defense-in-depth: keep signature data, strip runtime executable extractors.
62+
if (!inputRepo || typeof inputRepo !== "object") {
63+
return {};
6264
}
65+
const sanitized = {};
66+
Object.entries(inputRepo).forEach(([component, data]) => {
67+
if (!data || typeof data !== "object") {
68+
sanitized[component] = data;
69+
return;
70+
}
71+
const next = { ...data };
72+
if (next.extractors && typeof next.extractors === "object") {
73+
const { func, ...extractors } = next.extractors;
74+
next.extractors = extractors;
75+
}
76+
sanitized[component] = next;
77+
});
78+
return sanitized;
6379
}
6480

6581
function getFileName(url) {
@@ -69,6 +85,9 @@ function getFileName(url) {
6985
}
7086

7187
function scanUrlBackdoored(url) {
88+
if (!backdoorData || Object.keys(backdoorData).length === 0) {
89+
return [];
90+
}
7291
console.log("Scanning url for bd: ", url);
7392
const matches = Object.entries(backdoorData).filter(([title, advisories]) => {
7493
return advisories.some((advisory) => {
@@ -181,45 +200,18 @@ function astScan(content, details, contentResults) {
181200

182201
events.on("script-downloaded", function (details, content) {
183202
console.log("Scanning content of " + details.url + " ...");
184-
const bs = Date.now();
185203
var results = retire.scanFileContent(content, repo, hasher);
186204
astScan(content, details, results);
187205
if (results.length > 0) {
188206
events.emit("result-ready", details, results);
189207
return true;
190208
}
191-
events.emit("sandbox", details, content);
209+
// Intentionally disable sandbox runtime execution paths (eval/new Function).
210+
// Keep signature/hash/AST-based detections only.
192211
console.log(hasher.sha1(content) + " : " + details.url);
193212
return true;
194213
});
195214

196-
events.on("sandbox", function (details, content) {
197-
console.log("Sending to the sandbox");
198-
sandboxWin.postMessage(
199-
{
200-
tabId: details.tabId,
201-
script: content,
202-
url: details.url,
203-
repoFuncs: repoFuncs,
204-
},
205-
"*"
206-
);
207-
return true;
208-
});
209-
210-
window.addEventListener("message", function (evt) {
211-
if (evt.data.version) {
212-
var results = retire.check(evt.data.component, evt.data.version, repo);
213-
console.log("SANDBOX", stringifyResults(results));
214-
events.emit(
215-
"result-ready",
216-
{ url: evt.data.original.url, tabId: evt.data.original.tabId },
217-
results
218-
);
219-
}
220-
return true;
221-
});
222-
223215
function stringifyResults(results) {
224216
return results
225217
.map((x) => "\n" + x.component + ":" + x.version)
@@ -254,5 +246,3 @@ downloadRepo().then(() => {
254246
return false;
255247
});
256248
});
257-
258-
sandboxWin = window.document.getElementById("sandboxframe").contentWindow;

0 commit comments

Comments
 (0)