Is QR Code Generator safe?

Medium risk

QR Code Generator is medium risk. Opening the QR scanner's web-camera option calls the camera API from the current page. The manifest injects this script into every page and frame, but declared permissions list only context menus, not camera access.

QR Code Appv1.0.9Chrome 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-200
SourceAI SANDBOX

Camera Access Requested From Any Webpage

Opening the QR scanner's web-camera option calls the camera API from the current page.

The manifest injects this script into every page and frame, but declared permissions list only context menus, not camera access.

01EvidenceCAUSE EFFECT
What actually happens
You did this

You open the QR scanner overlay on a website and choose the web-camera scanner.

The camera scanner is available from the injected overlay, including a button labeled "Start Scanning with Web Camera".

The extension did this

The page-injected script asks the browser for video access.

The verified source path calls the camera request from `/static/content.js`, which the manifest loads on all URLs.

02EvidenceFIELD TABLE
Concrete fields in the camera request path
FieldValueWhy it matters
Where the scanner script runs
matches: ["<all_urls>"], all_frames: trueThe scanner interface is allowed to run on any website you visit, not only on an extension page.
When it is injected
run_at: "document_start"The scanner script is added early as each page loads, before you use the QR scanner overlay.
Manifest permissions
permissions: ["contextMenus"]The manifest evidence shows only a context-menu permission, so camera access is not visible as a declared extension permission there.
User-facing camera control
button.rb-qrsg-scan-with-camera-btn: "Start Scanning with Web Camera"The camera request is tied to the QR scanner's web-camera option that you can select in the overlay.
Camera request
getUserMedia({ audio: false, video: true })After that choice, the script asks for video access so the QR scanner can read from the camera.
03EvidenceCODE COMPARE
The code that does this

The content-script webcam path and page-wide manifest scope

What it actually does
Manifest loads the content script on every URL and framemanifest.json
"host_permissions": [
    "*://*/*",
    "<all_urls>"
],
"permissions": [
    "contextMenus"
],
"content_scripts": [
    {
      "matches": [
        "<all_urls>"
      ],
      "js": [
        "/static/content.js"
      ],
      "run_at": "document_start",
      "all_frames": true
    }
  ]
Readable camera request and scanner start functionstatic/content.js
this.checkAndScanWithWebCam = () => {
  navigator.mediaDevices.getUserMedia({
    audio: !1,
    video: !0
  }).then(t => {
    this.scanWithWebCam()
  }).catch(t => {
    "NotAllowedError" == t.name && k("Please allow or turn on your web camera")
  })
}, this.scanWithWebCam = () => {
  let t = f("#rb-qrsg-video");
  C(t), w(f(u)), w(f(_)), f(g).textContent = "Scanning...";
  let r = null;
  this.scanner.scanWithWebCam(t, a => {
    if (a && (C(f(".rb-qrsg-web-scanned-data-panel")), C(f(u)), !r)) {
      let i = f(u);
      i.width = t.width, i.height = t.height;
      let s = ((t, r = 1) => {
        let a = document.createElement("canvas");
        return a.id = "screenshot_canvas", a.width = t.clientWidth * r, a.height = t.clientHeight * r, a.getContext("2d").drawImage(t, 0, 0, a.width, a.height), a.toDataURL()
      })(t);
      return i.src = s, w(t), f(g).textContent = a, this.scanner.webCamScanner.pause(), C(f(_)), void(r = !0)
    }
  }, t => {
    console.log("Failed to Scan via Webcamera:", t)
  })
}
Readable route and click handlers that reach the camera requeststatic/content.js
this.listenForRouteChange = t => {
  let r = t.detail?.view;
  ({
    "rb-qrsg-webcamera-scanner": this.checkAndScanWithWebCam
  })[r]?.()
}, this.destroyWebCamScanning = t => {
  this.scanner.webCamScanner && this.scanner.destroyWebCamScan()
}, this.handleViewUnmounted = t => {
  let r = t.detail?.view;
  ({
    "rb-qrsg-webcamera-scanner": this.destroyWebCamScanning
  })[r]?.(r)
}
this.initialise = () => {
  this.initialised || (y("click", ".rb-qrsg-navigation-item>a", this.handleRoute), y("click", ".rb-qrsg-cancel-btn", this.closeOverlay), y("click", ".rb-qrsg-upload-btn", this.pickFile), y("change", h, this.scanFromFile), y("click", _, this.checkAndScanWithWebCam), y("click", ".rb-qrsg-copier", this.copyText), y("click", ".rb-qrsg-reset-btn", this.resetForm), y("click", m, this.downloadGeneratedQRCode), y("keyup", p, this.generateNewQRCode), window.addEventListener(i, this.listenForRouteChange), window.addEventListener(s, this.handleViewUnmounted), this.initialised = !0)
}
Readable overlay button presented to the userstatic/content.js
<button class="rb-qrsg-button-priary rb-qrsg-scan-with-camera-btn" type="button">Start Scanning with Web
    Camera</button>
04EvidenceARTIFACT
Check if you're affected

Checks an unpacked copy of this extension for the all-pages content script and camera request path shown above.

RequiresNode.js 18+
qr-camera-path-check.js · js
#!/usr/bin/env node
const fs = require('fs');
const path = require('path');

const root = process.argv[2];
if (!root) {
  console.error('Usage: node qr-camera-path-check.js /path/to/unpacked-extension');
  process.exit(2);
}

const manifestPath = path.join(root, 'manifest.json');
const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
const contentScripts = manifest.content_scripts || [];
const allUrlScript = contentScripts.find((entry) =>
  (entry.matches || []).includes('<all_urls>') &&
  (entry.js || []).some((script) => script.endsWith('content.js'))
);
const declaredPermissions = manifest.permissions || [];
const contentPath = path.join(root, 'static', 'content.js');
const content = fs.readFileSync(contentPath, 'utf8');

const findings = {
  contentScriptAllUrls: Boolean(allUrlScript),
  allFrames: Boolean(allUrlScript && allUrlScript.all_frames),
  runAt: allUrlScript && allUrlScript.run_at,
  declaredPermissions,
  declaresCameraPermission: declaredPermissions.includes('camera'),
  hasCameraButton: content.includes('rb-qrsg-scan-with-camera-btn'),
  hasWebcamRoute: content.includes('rb-qrsg-webcamera-scanner'),
  callsGetUserMediaVideo: /navigator\.mediaDevices\.getUserMedia\(\{\s*audio:!?[!a-zA-Z0-9]+,\s*video:!?[!a-zA-Z0-9]+\}/.test(content) || content.includes('navigator.mediaDevices.getUserMedia({audio:!1,video:!0}')
};

console.log(JSON.stringify(findings, null, 2));

if (findings.contentScriptAllUrls && findings.hasCameraButton && findings.hasWebcamRoute && findings.callsGetUserMediaVideo && !findings.declaresCameraPermission) {
  process.exit(1);
}
How to run it
  1. 1
    node qr-camera-path-check.js /path/to/unpacked-extension

What it can do

Permissions this extension asks for, as declared in version 1.0.5. Asking for a permission is not a finding on its own - it is what the extension can do if it chooses to. The current listed version is 1.0.9, which we have not unpacked yet.

  • Read and change your data on every site you visit

    *://*/* and 1 more

  • Add items to the right-click menu

    contextMenus

Updated 30 September 2026hoeiookpkijlnjdafhaclpdbfflelmci