CVE-2024-34714 (published 2024-05-14T16:17Z)

The Hoppscotch Browser Extension is a browser extension for Hoppscotch, a community-driven end-to-end open-source API development ecosystem. Due to an oversight during a change made to the extension in the commit d4e8e4830326f46ba17acd1307977ecd32a85b58, a critical check for the origin list was missed and allowed for messages to be sent to the extension which the extension gladly processed and responded back with the results of, while this wasn't supposed to happen and be blocked by the origin not being present in the origin list.\n\nThis vulnerability exposes Hoppscotch Extension users to sites which call into Hoppscotch Extension APIs internally. This fundamentally allows any site running on the browser with the extension installed to bypass CORS restrictions if the user is running extensions with the given version. This security hole was patched in the commit 7e364b928ab722dc682d0fcad713a96cc38477d6 which was released along with the extension version `0.35`. As a workaround, Chrome users can use the Extensions Settings to disable the extension access to only the origins that you want. Firefox doesn't have an alternative to upgrading to a fixed version.


Weakness information:
cwe_id: NVD-CWE-noinfo
cwe_name: Insufficient Information
description: There is insufficient information about the issue to classify it; details are unkown or unspecified.
extended_description: Insufficient Information

Fix information:
repo_url: https://github.com/hoppscotch/hoppscotch-extension
commit_details: repo_url: https://github.com/hoppscotch/hoppscotch-extension
author: Akash K
author_date: 2024-05-06 20:44:58+05:30
msg: fix: disable postMessage from unknown origin (#295)
repository: repo_url: https://github.com/hoppscotch/hoppscotch-extension
repo_name: hoppscotch/hoppscotch-extension
description: 🧩 Browser extensions to provide more capabilities to https://hoppscotch.io
repo_language: TypeScript
owner: hoppscotch
file_changes: filename: manifest.common.json
change_type: ModificationType.MODIFY
diff: @@ -1,7 +1,7 @@
 {
   "manifest_version": 3,
   "name": "Hoppscotch Browser Extension",
-  "version": "0.34",
+  "version": "0.35",
   "description": "Provides more capabilities for Hoppscotch",
   "icons": {
     "16": "icons/icon-16x16.png",

programming_language: JavaScript
filename: package.json
change_type: ModificationType.MODIFY
diff: @@ -1,6 +1,6 @@
 {
   "name": "hoppscotch-extension",
-  "version": "0.34.0",
+  "version": "0.35.0",
   "description": "Provides more features to the Hoppscotch webapp (https://hoppscotch.io/)",
   "scripts": {
     "clean": "rimraf dist .parcel-cache",

programming_language: JavaScript
filename: contentScript.ts
change_type: ModificationType.MODIFY
diff: @@ -73,8 +73,15 @@ function main() {
     }
   })
 
-  window.addEventListener("message", (ev) => {
-    if (ev.source !== window || !ev.data) {
+  window.addEventListener("message", async (ev) => {
+    const originList = await getOriginList()
+    let url = new URL(window.location.href)
+
+    const originType = originList.includes(url.origin)
+      ? "VALID_ORIGIN"
+      : "UNKNOWN_ORIGIN"
+
+    if (ev.source !== window || !ev.data || originType != "VALID_ORIGIN") {
       return
     }
 

programming_language: JavaScript
filename: hookContent.js
change_type: ModificationType.MODIFY
diff: @@ -36,7 +36,7 @@
   }
 
   window.__POSTWOMAN_EXTENSION_HOOK__ = {
-    getVersion: () => ({ major: 0, minor: 34 }),
+    getVersion: () => ({ major: 0, minor: 35 }),
 
     decodeB64ToArrayBuffer: (input, ab) => {
       const keyStr =

programming_language: JavaScript
repo_url: https://github.com/hoppscotch/hoppscotch-extension
commit_details: repo_url: https://github.com/hoppscotch/hoppscotch-extension
author: Akash K
author_date: 2023-12-13 16:21:20+05:30
msg: chore: firefox manifest v3 support (#232)

Co-authored-by: Andrew Bastin <andrewbastin.k@gmail.com>
repository: repo_url: https://github.com/hoppscotch/hoppscotch-extension
repo_name: hoppscotch/hoppscotch-extension
description: 🧩 Browser extensions to provide more capabilities to https://hoppscotch.io
repo_language: TypeScript
owner: hoppscotch
file_changes: filename: .parcelrc
change_type: ModificationType.MODIFY
diff: @@ -1,6 +1,11 @@
 {
   "extends": "@parcel/config-default",
   "transformers": {
-    "*.ttf": ["@parcel/transformer-raw"]
-  }
-}
\ No newline at end of file
+    "*.ttf": [
+      "@parcel/transformer-raw"
+    ]
+  },
+  "reporters": [
+    "./mergeManifest.js"
+  ]
+}

programming_language: JavaScript
filename: manifest.chrome.json
change_type: ModificationType.ADD
diff: @@ -0,0 +1,5 @@
+{
+  "background": {
+    "service_worker": "index.js"
+  }
+}

programming_language: CSS
filename: manifest.common.json
change_type: ModificationType.RENAME
diff: @@ -1,32 +1,19 @@
 {
   "manifest_version": 3,
   "name": "Hoppscotch Browser Extension",
-  "version": "0.26",
+  "version": "0.27",
   "description": "Provides more capabilities for Hoppscotch",
   "icons": {
     "16": "icons/icon-16x16.png",
     "48": "icons/icon-48x48.png",
     "128": "icons/icon-128x128.png"
   },
-  "background": {
-    "service_worker": "index.js"
-  },
   "action": {
     "default_title": "Hoppscotch Extension",
     "default_popup": "popup.html"
   },
   "permissions": ["storage", "tabs", "cookies", "scripting"],
   "host_permissions": ["<all_urls>"],
-  "applications": {
-    "gecko": {
-      "id": "postwoman-firefox@postwoman.io"
-    }
-  },
-  "browser_specific_settings": {
-    "gecko": {
-      "id": "postwoman-firefox@postwoman.io"
-    }
-  },
   "web_accessible_resources": [
     {
       "resources": ["*.js.map"],

programming_language: JavaScript
filename: manifest.firefox.json
change_type: ModificationType.ADD
diff: @@ -0,0 +1,10 @@
+{
+  "background": {
+    "scripts": ["index.js"]
+  },
+  "browser_specific_settings": {
+    "gecko": {
+      "id": "postwoman-firefox@postwoman.io"
+    }
+  }
+}

programming_language: TypeScript
filename: mergeManifest.js
change_type: ModificationType.ADD
diff: @@ -0,0 +1,50 @@
+const { Reporter } = require("@parcel/plugin")
+const fs = require("fs").promises
+
+module.exports = new Reporter({
+  async report({ event }) {
+    const target = process.env.HOPP_EXTENSION_TARGET
+
+    if (!target) {
+      return
+    }
+
+    if (event.type == "buildSuccess") {
+      const manifestCommon = (
+        await fs.readFile("./manifest.common.json")
+      ).toString()
+
+      let targetManifestFilePath
+
+      if (target == "CHROME") {
+        targetManifestFilePath = "./manifest.chrome.json"
+      } else if (target == "FIREFOX") {
+        targetManifestFilePath = "./manifest.firefox.json"
+      } else {
+        return
+      }
+
+      const targetSpecificManifest = (
+        await fs.readFile(targetManifestFilePath)
+      ).toString()
+
+      const manifestFinal = JSON.stringify(
+        {
+          ...JSON.parse(manifestCommon),
+          ...JSON.parse(targetSpecificManifest),
+        },
+        null,
+        2
+      )
+
+      // make sure the ./dist folder exists
+      await fs.mkdir("./dist").catch(() => {})
+
+      await fs.writeFile("./dist/manifest.json", manifestFinal, {
+        flag: "w",
+      })
+
+      process.stdout.write("💚 Manifest File Written Successfully")
+    }
+  },
+})

programming_language: TypeScript
filename: package.json
change_type: ModificationType.MODIFY
diff: @@ -1,16 +1,18 @@
 {
   "name": "hoppscotch-extension",
-  "version": "0.26.0",
+  "version": "0.27.0",
   "description": "Provides more features to the Hoppscotch webapp (https://hoppscotch.io/)",
   "scripts": {
-    "clean": "rimraf dist",
-    "build": "pnpm exec parcel build src/* --dist-dir dist/ && pnpm exec copyfiles manifest.json dist && pnpm exec copyfiles icons/* dist"
+    "clean": "rimraf dist .parcel-cache",
+    "build:chrome": "HOPP_EXTENSION_TARGET=CHROME parcel build src/* --dist-dir dist/ && copyfiles icons/* dist",
+    "build:firefox": "HOPP_EXTENSION_TARGET=FIREFOX parcel build src/* --dist-dir dist/ && copyfiles icons/* dist"
   },
   "author": "Andrew Bastin",
   "license": "MIT",
   "devDependencies": {
     "@parcel/config-default": "^2.10.0",
     "@parcel/core": "^2.10.0",
+    "@parcel/plugin": "^2.10.0",
     "@parcel/transformer-raw": "^2.10.0",
     "@types/chrome": "^0.0.246",
     "@types/node": "^17.0.23",

programming_language: JavaScript
filename: pnpm-lock.yaml
change_type: ModificationType.MODIFY
diff: @@ -19,6 +19,9 @@ devDependencies:
   '@parcel/core':
     specifier: ^2.10.0
     version: 2.10.0
+  '@parcel/plugin':
+    specifier: ^2.10.0
+    version: 2.10.0(@parcel/core@2.10.0)
   '@parcel/transformer-raw':
     specifier: ^2.10.0
     version: 2.10.0(@parcel/core@2.10.0)

programming_language: CoffeeScript
filename: contentScript.ts
change_type: ModificationType.MODIFY
diff: @@ -1,3 +1,16 @@
+const fs = require("fs")
+
+const hookContent = fs.readFileSync(__dirname + "/hookContent.js", {
+  encoding: "utf-8",
+})
+
+const hookContentInvalidOrigin = fs.readFileSync(
+  __dirname + "/hookContentInvalidOrigin.js",
+  {
+    encoding: "utf-8",
+  }
+)
+
 export type HOOK_MESSAGE = {
   type: "execute_hook"
   origin_type: "VALID_ORIGIN" | "UNKNOWN_ORIGIN"
@@ -27,12 +40,23 @@ async function injectHoppExtensionHook() {
 
   let url = new URL(window.location.href)
 
-  chrome.runtime.sendMessage(<HOOK_MESSAGE>{
-    type: "execute_hook",
-    origin_type: originList.includes(url.origin)
-      ? "VALID_ORIGIN"
-      : "UNKNOWN_ORIGIN",
-  })
+  const originType = originList.includes(url.origin)
+    ? "VALID_ORIGIN"
+    : "UNKNOWN_ORIGIN"
+
+  if (process.env.HOPP_EXTENSION_TARGET === "FIREFOX") {
+    const script = document.createElement("script")
+    script.textContent = originList.includes(url.origin)
+      ? hookContent
+      : hookContentInvalidOrigin
+    document.documentElement.appendChild(script)
+    script.parentNode.removeChild(script)
+  } else {
+    chrome.runtime.sendMessage(<HOOK_MESSAGE>{
+      type: "execute_hook",
+      origin_type: originType,
+    })
+  }
 }
 
 window.addEventListener("message", (ev) => {
@@ -74,7 +98,7 @@ window.addEventListener("message", (ev) => {
   }
 })
 
-const VERSION = { major: 0, minor: 26 }
+const VERSION = { major: 0, minor: 27 }
 
 injectHoppExtensionHook()
 

programming_language: JavaScript
filename: hookContent.js
change_type: ModificationType.MODIFY
diff: @@ -36,7 +36,7 @@
   }
 
   window.__POSTWOMAN_EXTENSION_HOOK__ = {
-    getVersion: () => ({ major: 0, minor: 26 }),
+    getVersion: () => ({ major: 0, minor: 27 }),
 
     decodeB64ToArrayBuffer: (input, ab) => {
       const keyStr =

programming_language: JavaScript