Is iorad — the tutorial builder safe?

Medium risk

iorad — the tutorial builder is medium risk. Each time iorad starts, it fetches a 470KB config from iorad.com with URL regex patterns controlling which content scripts inject where. The server can change this without a Store update. A compromise or MITM could redirect injection.

iorad.extensionv2.0.0.5666Chrome Web Store
45Risk

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

Publishers can request a review.

Findings

SeverityMEDIUM
ClassUNWANTED
TypeUnexpected
CWECWE-829
SourceAI SANDBOX

Server-Controlled Content Script Injection Targeting

Each time iorad starts, it fetches a 470KB config from iorad.com with URL regex patterns controlling which content scripts inject where.

The server can change this without a Store update.

A compromise or MITM could redirect injection.

01EvidenceCAUSE EFFECT
What actually happens
You did this

The extension's background service worker starts and calls requireIntegrations().

This happens automatically on every browser launch or extension reload, before any user interaction.

The extension did this

The iorad server returns a 470 KB JSON payload containing URL regex patterns that tell the extension which content scripts to inject into which tabs.

These patterns take effect immediately and persist until the next restart, no Chrome Web Store update is required to change them.

02EvidenceNETWORK CAPTURE
Captured request
GEThttps://www.iorad.com/api/extensions/configsAndSiteTheme
HTTP 200, 470,662 bytes JSON. Top-level keys include configs[], each entry has an enabled flag and a chromeLazyLoaders array. Each chromeLazyLoaders entry is an array of injection condition objects with url (regex string), topFrame (bool), inactiveTab (bool), plus the module name to inject (e.g. "integrations", "topFrame"). Live example pattern observed: coassemble.com course URLs mapped to the integrations module.
Headers
Acceptapplication/json, text/plain, */*
03EvidenceCODE COMPARE
The code that does this

Client-side regex compilation and injection dispatch

What it actually does
Annotated — what each step does
// 1. Fetch server config (no signature / integrity check)
const config = await fetch('https://www.iorad.com/api/extensions/configsAndSiteTheme');
const { configs } = await config.json();

// 2. For every enabled integration entry in the 470 KB response…
for (const integration of configs.filter(c => c.enabled)) {
  for (const loaderConditions of integration.chromeLazyLoaders) {
    // 3. Server-supplied url string is compiled to a live RegExp — no sanitisation
    const conditions = loaderConditions.map(cond => {
      if (cond.url && typeof cond.url === 'string') {
        cond.url = new RegExp(cond.url); // ← server controls this pattern
      }
      return cond;
    });
    // 4. Condition object drives chrome.scripting.executeScript
    //    into any tab whose URL matches the server-compiled regex
    lazyLoader.require(...conditions); // → executeScript
  }
}
04EvidenceFIELD TABLE
Fields the server controls in each chromeLazyLoaders entry
FieldValueWhy it matters
URL match pattern
https://coassemble\.com/courses/[^/]+/[^/]+A server-supplied regex; compiled client-side, it governs which tabs get the injected script. Changing it redirects injection silently.
Module name
integrationsName of the pre-registered content script to inject on a URL match, limited to the 11 bundled modules (e.g. integrations, topFrame, player).
Frame targeting
topFrame: true, inactiveTab: falseWhether the script targets the top frame or sub-frames, and whether it fires on inactive tabs.
05EvidenceTHIRD PARTY LIST
Server that controls injection targeting
  • www.iorad.com

    iorad's production API server. Serves the configsAndSiteTheme endpoint whose response sets which pre-registered scripts inject into which URL patterns, across all installs.

Updated 17 September 2026kjfmedbganalpkohkeghhpppicoigdal