Security Alert: Confirmed Malware
Web paint
ID: colbejldlbhdkjhdndknbminnlbbkecj
Supported Languages
Extension Info & Metadata
Publisher Contextual Analysis
- Author
- Diana KrievView Profile
- MX records exist
- Yes
- Domain exists
- Yes
- Is disposable
- No
- Is role-based
- No
- Mailbox exists
- Yes
Draw on any web page. Annotate the web!
Web paint allows you to draw on web pages! Use a powerful image editing tool right in the browser. ===== Features ===== โญ Paint tools: pencil, eyedropper, text, line, arrows, and more โญ Customize tools: size and color โญ Save to file or copy to clipboard (!) Please note: due to security restrictions the tool doesnโt work on Chrome Webstore or system browser pages e.g. Settings.
The `processQueue` function constructs a base64-encoded query-string payload containing the extension's unique runtime ID, the installation action reason (e.g. 'install', 'update'), and a timestamp โ formatted as a URL parameter `p=<base64>`. While the variable `b` is assigned but not used for an explicit network call in this version, the infrastructure is a canonical install-event telemetry fingerprint: `initListeners` queues every `onInstalled` event, and `initStorage` processes the queue on startup. The stripped/missing send target is a common pattern in extensions that remove the exfiltration URL to pass review while preserving the payload-building machinery.
processQueue() { for (; NP.queue.length > 0;) { const a = NP.queue.shift(); if (!a.type || a.type != "action") return !0; const b = `p=${encodeURIComponent(btoa(JSON.stringify({id:chrome.runtime.id,action:a.action,t:Date.now()})))}` }}, initListeners() { chrome.runtime.onInstalled.addListener(a => { NP.queue.push({ type: "action", action: a.reason }), NP.queueProcessorReady && NP.processQueue() })}, initStorage() { chrome.storage.local.get(a => { if (a && a.config) { NP.config = a.config; this.saveConfig(); NP.queueProcessorReady = !0; NP.processQueue() } })}The extension explicitly declares `'unsafe-eval'` in its Content Security Policy, allowing dynamic code execution via `eval()`, `new Function()`, `setTimeout(string)`, etc. For a drawing/paint extension there is no legitimate reason to require `unsafe-eval`. Combined with the broad `<all_urls>` host permission and the background page's ability to inject scripts into any tab, this significantly lowers the bar for code injection if any part of the extension is compromised or if a dynamic code path is introduced.
{ "content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'"}The content script stores a full base64-encoded PNG snapshot of the canvas (which is overlaid on top of the visited page) in the page's `localStorage`, keyed by `WP_CRX_STORAGE_SNAPSHOT_<pathname>`. Because the canvas captures whatever the user drew on that specific page URL, the set of keys present in `localStorage` across browsing sessions constitutes a de-facto record of which page paths the user has visited and annotated. On subsequent visits the snapshot is retrieved and reloaded, meaning page-level localStorage entries persist indefinitely. Any script on the same origin can read these keys.
persistLocalStorage() { const t = this.canvas.toDataURL(); try { p.localStorage.setItem(`WP_CRX_STORAGE_SNAPSHOT_${p.location.pathname}`, t) } catch (e) { try { p.localStorage.clear(), p.localStorage.setItem(`WP_CRX_STORAGE_SNAPSHOT_${p.location.pathname}`, t) } catch (e) {} }}The content script reads from and writes to `unsafeWindow.CTRL_HIDDEN` and `unsafeWindow.NOTEPAD_INIT`. `unsafeWindow` is a privileged Firefox API that exposes the raw page-level JavaScript execution context, bypassing the normal content-script/page-script isolation boundary. Writing extension state into `unsafeWindow` allows arbitrary page-level scripts to observe and potentially manipulate the extension's internal state, and reading from it allows the page to signal the extension โ creating a bidirectional covert channel between untrusted page code and the privileged extension.
typeof unsafeWindow !== "undefined" && unsafeWindow !== null ? unsafeWindow.CTRL_HIDDEN ? n.NOTEPAD.showControlPanel() : unsafeWindow.NOTEPAD_INIT || (n.NOTEPAD = t(n), n.NOTEPAD.init()) : (void 0 !== n.NOTEPAD && n.NOTEPAD !== null || (n.NOTEPAD = t(n)), n.NOTEPAD.controlPanelHidden ? n.NOTEPAD.showControlPanel() : n.NOTEPAD.initialized || n.NOTEPAD.init())The eyedropper feature calls `captureVisibleTab` to take a full screenshot of the currently active tab, then renders the entire screenshot into a canvas element temporarily appended to the background page's DOM. Although the canvas is removed after the pixel sample is taken, the full tab screenshot (as a data URL) is held in memory during the operation with no bounds checking on coordinates. Because the `<all_urls>` permission is active, this capture applies to any tab including banking, authentication, and sensitive pages โ and the full data URL `a` is available in the closure throughout the async image load cycle.
getPixelColor(b, d) { global.tabs.captureVisibleTab(null, null, a => { const c = document.createElement("canvas"); const f = c.getContext("2d"); const g = new Image; document.documentElement.appendChild(c), g.src = a, g.onload = function onload() { c.width = g.naturalWidth, c.height = g.naturalHeight, f.drawImage(g, 0, 0); const h = f.getImageData(0, 0, c.width, c.height); const e = 4 * (b.y * h.width + b.x); const i = h.data; if (typeof d === "function") { const j = { r: i[e], g: i[e + 1], b: i[e + 2], a: i[e + 3] }; document.documentElement.removeChild(c), d(j) } } })}By severity
Versions scanned
Showing 2 of 3 scanned versions with more than one unique finding. Counts are unique findings that include each version.
| Extension Version | Code Review Findings |
|---|---|
| 0.12.6 | 2 |
| 0.12.5 | 5 |
Files with findings
3 distinct paths โ top paths by unique finding count:
- js/inject.js3
- bg.js2
- manifest.json2
URLs
View the external URLs this extension communicates with to understand its network activity and data interactions.
Gain full insight into all external connections.
Upgrade for full visibility.
Gain full insight into all external connections.
Upgrade for full visibility.
Code Diff
Compare extension code between any two versions.
No comparable text files found between these versions.
Browse and explore files within this extension package
Gain full insight into all external connections.
Upgrade for full visibility.