chrome-ext-messaging — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited chrome-ext-messaging (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.
All extension contexts are strictly siloed — no shared memory. Communication happens exclusively through async message passing with JSON-serializable data. Choose the right pattern for each use case and enforce type safety through Protocol Maps.
For standard async tasks (popup requests data from service worker, content script sends page data):
// Sender (popup or content script)
const response = await chrome.runtime.sendMessage({
action: 'getData',
query: 'recent',
});
// Receiver (service worker)
chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => {
if (msg.action === 'getData') {
fetchData(msg.query).then(sendResponse);
return true; // CRITICAL: keeps channel open for async response
}
});To send to a specific tab's content script:
chrome.tabs.sendMessage(tabId, { action: 'highlight', selector: '.target' });For continuous data streams (live AI chat, progress tracking, persistent connections):
// Initiate connection
const port = chrome.runtime.connect({ name: 'ai-chat' });
// Send messages
port.postMessage({ prompt: 'Explain this page' });
// Receive responses
port.onMessage.addListener((msg) => {
console.log('Response chunk:', msg.text);
});
// Detect disconnection
port.onDisconnect.addListener(() => {
console.log('Connection closed');
});| Pattern | Use Case | Lifecycle |
|---|---|---|
sendMessage | One-off request/response | Single exchange, then done |
connect / Port | Streaming data, monitoring | Persistent until disconnect |
Use @webext-core/messaging to define TypeScript-enforced message contracts:
// src/utils/messaging.ts
import { defineExtensionMessaging } from '@webext-core/messaging';
interface ProtocolMap {
getData: (query: string) => DataResult;
updateSettings: (settings: Settings) => void;
getTabInfo: () => TabInfo;
}
export const { sendMessage, onMessage } = defineExtensionMessaging<ProtocolMap>();Usage across contexts:
// Sender — compiler verifies payload and return types
const result = await sendMessage('getData', 'recent');
// Receiver — handler signature enforced by TypeScript
onMessage('getData', ({ data: query }) => {
return fetchData(query); // Must return DataResult
});onMessage listener performs async work before calling sendResponse, the listener MUST return true to keep the message channel open.async listener that doesn't explicitly return a value resolves to undefined, sending null to the sender and immediately closing the channel.chrome.runtime.lastError explicitly.action property for routingto and from for multi-context routing~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.