chrome-ext-service-worker — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited chrome-ext-service-worker (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
MV3 replaced persistent background pages with ephemeral, event-driven service workers. They wake to process events and terminate after ~30 seconds of inactivity. All in-memory state is lost on termination. Code must be structured around this fundamental constraint.
[Event occurs] → [Worker starts] → [Script executes top-to-bottom]
→ [Registered listeners fire] → [~30s idle] → [Worker terminates]
→ [All global variables lost]Every handler must assume zero prior state. Rehydrate from storage at the start of every event.
The browser scans for listeners on the first turn of the event loop. Listeners inside promises, callbacks, setTimeout, or async functions will NOT be registered in time.
// CORRECT — synchronous, top-level
export default defineBackground(() => {
chrome.runtime.onMessage.addListener(handleMessage);
chrome.alarms.onAlarm.addListener(handleAlarm);
chrome.runtime.onInstalled.addListener(handleInstall);
});
// WRONG — async, buried inside callback
export default defineBackground(async () => {
await someSetup();
// TOO LATE — worker may have already handled the event
chrome.runtime.onMessage.addListener(handleMessage);
});Standard timers are canceled on termination. Replace with chrome.alarms:
// WRONG — unreliable
setTimeout(() => checkForUpdates(), 60000);
// CORRECT — survives worker restarts
chrome.alarms.create('check-updates', { periodInMinutes: 1 });
chrome.alarms.onAlarm.addListener((alarm) => {
if (alarm.name === 'check-updates') checkForUpdates();
});// WRONG — lost on restart
let userPrefs = {};
// CORRECT — persist to storage
async function getPrefs() {
const { prefs } = await chrome.storage.local.get('prefs');
return prefs ?? DEFAULT_PREFS;
}XMLHttpRequest is unavailable in service workers. All network requests use fetch().
"Hydrate, Don't Store" — every event handler reads current state from storage:
chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => {
if (msg.action === 'getStatus') {
chrome.storage.local.get('status').then(({ status }) => {
sendResponse(status ?? { active: false });
});
return true; // async response
}
});For tasks requiring DOM that the service worker cannot access:
async function parseHTML(html: string): Promise<string> {
// Create offscreen document if not exists
const contexts = await chrome.runtime.getContexts({
contextTypes: [chrome.runtime.ContextType.OFFSCREEN_DOCUMENT],
});
if (!contexts.length) {
await chrome.offscreen.createDocument({
url: 'offscreen.html',
reasons: [chrome.offscreen.Reason.DOM_PARSER],
justification: 'Parse HTML content',
});
}
// Delegate via message passing
return chrome.runtime.sendMessage({ action: 'parseHTML', html });
}Valid reasons: CLIPBOARD, DOM_PARSER, AUDIO_PLAYBACK, DOM_SCRAPING, BLOBS, GEOLOCATION, WORKERS, and more.
Only one offscreen document can exist at a time.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.