Is HTML editor WebStudio for Webpages safe?
HTML editor WebStudio for Webpages sends the URL of every site you visit to a tracking server on each tab switch.
A background script hooks tab activation and navigation events for every tab, and for essentially every site it sends the page URL, hex-encoded, along with a persistent per-install ID, to stream.redcoolmedia.net. This tracking works across all sites because the extension only requests the 'tabs' permission, and it runs by default with no mention in the extension's store listing. The tracking server's response can also trigger the extension to redirect the active tab to a redcoolmedia.net page.
AI-generated. Findings may contain errors. Those marked Verified have been manually reviewed.
Publishers can request a review.
Findings
WebStudio HTML editor reports every site you visit to redcoolmedia.net
Code analysis shows the background script hex-encodes the URL of every http(s) page you switch to or navigate to and sends it to a redcoolmedia.net server with a persistent per-install ID.
Only redcoolmedia.net's own pages are excluded.
- Severity
- High unwanted
- Type
- Unexpected
- CWE
- CWE-359
- Source
- Static analysis
You switch to a tab or navigate within it to any http(s) page that isn't on redcoolmedia.net.
This fires on ordinary browsing, not just while using the extension's own editor.
The extension hex-encodes the page's full URL and sends it to stream.redcoolmedia.net with a persistent per-install ID.
The request repeats on every qualifying tab switch or navigation for as long as the extension is installed.
- Site you visited687474703a2f2f6578616d706c652e636f6d2f6c6f67696e
The full address of the page you just opened or switched to, hex-encoded so it isn't plainly readable in a casual look at network logs.
- Persistent install IDk3n9dxaq7m
A random ID generated once per install and reused on every request, letting all your browsing be linked together over time.
- Full outbound requesthttps://stream.redcoolmedia.net/api/webstudiou.php?l=687474703a2f2f6578616d706c652e636f6d2f6c6f67696e&hex=1&u=k3n9dxaq7m
Combines the encoded URL and install ID into one request sent to redcoolmedia.net's server.
Navigation listener and hex-encoded beacon in web.js
Per-tab listener, renamed for clarity
web.js// Fires whenever a tab is activated or its URL changes.function onTabUrlKnown(tabId) { chrome.tabs.get(tabId, function (tab) { const isTrackable = tab.url.indexOf("redco") == -1 && // skip redcoolmedia.net's own pages tab.url.indexOf("http") !== -1 && // only http(s) pages lastSeenUrl != tab.url; // skip duplicate re-fires if (isTrackable) { sendVisitedUrl(tab.url); lastSeenUrl = tab.url; } });}chrome.tabs.onActivated.addListener(function (activeInfo) { onTabUrlKnown(activeInfo.tabId);});chrome.tabs.onUpdated.addListener(function (tabId, changeInfo, tab) { onTabUrlKnown(tabId);});Beacon function, renamed for clarity
web.jsasync function sendVisitedUrl(visitedUrl) { // installConfig.installId: random 10-char ID created once per install. // installConfig.trackingEnabled: '1' unless the user unchecked the // options-page toggle; defaults to '1' on first run. let installConfig = (await chrome.storage.local.get(["redcool_key"]))["redcool_key"] || {}; if (!installConfig.installId) { installConfig.installId = randomString(10); } if (!installConfig.trackingEnabled) { installConfig.trackingEnabled = "1"; } await chrome.storage.local.set({ redcool_key: installConfig }); if (installConfig.trackingEnabled == "0") return; // user opted out // Hex-encode the visited URL, attach the persistent install ID, send it. await fetch( "https://stream.redcoolmedia.net/api/webstudiou.php?l=" + hexEncode(visitedUrl) + "&hex=1&u=" + installConfig.installId );}Decodes a captured stream.redcoolmedia.net/api/webstudiou.php request URL back to the plaintext site that was visited and the persistent install ID it was tied to.
- Python 3.6+
#!/usr/bin/env python3"""Decode a stream.redcoolmedia.net/api/webstudiou.php request URL back to theplaintext site visited and the persistent per-install ID it was sent with.Usage: python3 decode_redcool_request.py "<request_url>""""import sysfrom urllib.parse import urlparse, parse_qsdef decode(request_url: str) -> None: query = parse_qs(urlparse(request_url).query) hex_url = query.get("l", [None])[0] install_id = query.get("u", [None])[0] if not hex_url: print("No 'l' query parameter found; this doesn't look like a webstudiou.php request.") return site_url = bytes.fromhex(hex_url).decode("utf-8", errors="replace") print(f"Site visited: {site_url}") print(f"Persistent install ID: {install_id}")if __name__ == "__main__": if len(sys.argv) != 2: print("Usage: python3 decode_redcool_request.py <request_url>") sys.exit(1) decode(sys.argv[1])- 1Copy a captured request URL to stream.redcoolmedia.net/api/webstudiou.php from a network log.
- 2Run: python3 decode_redcool_request.py "<url>".
- 3The script prints the plaintext site URL and the install ID it was linked to.
Static analysis finding. This behaviour was identified by reading the shipped extension code and has not yet been reproduced in a live run. The trigger conditions and the exact data sent are read from the code, not from an observed capture.
What it can do
Permissions this extension asks for, as declared in version 1.4.7. Asking for a permission is not a finding on its own - it is what the extension can do if it chooses to.
Store data in your browser
storage
See the address and title of every tab you have open
tabs
Where it sends data
Destinations our analysis observed HTML editor WebStudio for Webpages contacting. Sending data somewhere is not a finding on its own - an extension that syncs your settings has to talk to its own server - but it is where your data can go, and who else it goes to.
- www.redcoolmedia.net
HTML editor WebStudio for Webpages sends data to www.redcoolmedia.net. 16 other extensions we have analyzed send data here.
- stream.redcoolmedia.net
HTML editor WebStudio for Webpages sends data to stream.redcoolmedia.net. 10 other extensions we have analyzed send data here.