Is フリマアシスト safe?

Medium risk

フリマアシスト reads the user's Mercari auth token from localStorage and routes authenticated Mercari API calls through the developer's own Google Cloud Function.

The extension's content script extracts the Mercari login token stored in the browser and attaches it to requests, which are AES-encrypted with a hardcoded key and forwarded to asia-northeast1-furima-assist-free.cloudfunctions.net. This cloud proxy then makes authenticated calls to api.mercari.jp on the user's behalf. Separately, the extension fetches a remote configuration from kiyomaro.net every minute to control ad banners injected into flea market pages.

きよまろv3.69.1Chrome Web Store
49Risk
Who publishes it

きよまろ - 1 other listing from the same operator, none carrying a finding

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

Publisher
きよまろ

Same store account

1 other listing published from this account, 2k+ users between them, none of them carrying a finding.

Shared hosts - 9 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.

admin.thebase.in
Also called by 1 other listing: フリマ王-フリマ(メルカリ・ラクマ)で使えるコピー出品機能
asia-northeast1-furima-assist-free.cloudfunctions.net
Also called by 1 other listing: FurimAuto(フリマート)
admin.thebase.com
Also called by 3 other listings, including フリマ王-フリマ(メルカリ・ラクマ)で使えるコピー出品機能, Clickpost Bridge
auctions.c.yimg.jp
Also called by 3 other listings, including フリマPro, FurimAuto(フリマート)
creema.jp
Also called by 3 other listings: フリマ王-フリマ(メルカリ・ラクマ)で使えるコピー出品機能, Clickpost Bridge, フリマPro
dashboard.stores.jp
Also called by 3 other listings: フリマ王-フリマ(メルカリ・ラクマ)で使えるコピー出品機能, Clickpost Bridge, フリマPro
minne.com
Also called by 3 other listings, including フリマPro
stores.jp
Also called by 3 other listings, including Clickpost Bridge
paypayfleamarket-sec.yahoo.co.jp
Also called by 5 other listings, including FurimAuto(フリマート)

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

Publishers can request a review.

Findings

Ad Banner Content Fetched from Developer's Remote Server

On flea market sites, the extension polls kiyomaro.net every minute by default for config data controlling injected ad banners and links.

We captured 53 such requests; a server change alters injections without a Store update.

Severity
Medium unwanted
Type
Unexpected
CWE
CWE-829
Source
Dynamic sandbox
What actually happens
You did this

You open a supported flea market page such as jp.mercari.com.

The content script and background service worker activate for the matched domain.

The extension did this

The extension fetches kiyomaro.net/bt/button.json and caches the returned configuration, which determines what banner images and links are injected into the page.

If the remote config is unavailable, the last cached version stored in chrome.storage.local is used.

Captured request
GEThttps://kiyomaro.net/bt/button.json?t=1748932847123

Returns a JSON object with a furimaAssist.free field containing banner image URLs, link destinations, and optional text. Observed 38 HTTP 200 and 15 HTTP 429 responses across 53 requests during dynamic analysis.

When this fires

Every 1 minute

The background worker re-fetches the remote config at most once per minute (default). The poll interval itself is configurable via the fetchIntervalMinutes field returned by the same remote endpoint.

The code that does this

Remote config fetch and storage in background service worker

Readable version
const o = async () => {  const e = "https://kiyomaro.net/bt/button.json?t=" + (new Date).getTime();  try {    const r = await fetch(e);    return await r.json()  } catch (e) {    console.error("error", e)  }  return {}},c = async e => {  await Object(n.g)({ af: JSON.stringify(e) }) // write to chrome.storage.local},i = async () => {  var e, r;  const t = 60 * ((null === (e = properties) || void 0 === e || null === (r = e.af) || void 0 === r ? void 0 : r.fetchIntervalMinutes) || 1) * 1e3  // poll interval controlled by the remote config itself
Domains contacted for remote ad configuration
    • kiyomaro.net

    Developer-operated server. Returns the furimaAssist.free JSON object controlling banner image URLs, link destinations, poll interval, and related ad display settings.

    • furima-assist.com

    Developer-operated server. Hosts the default banner image and link assets referenced in property.js; images are fetched via background relay before insertion.

Mercari API Calls Proxied Through Developer's Cloud Function

On Mercari, the extension encrypts requests (URL, method, body, timestamp) with an embedded key and hands them to a developer-run Google Cloud Function, which decrypts and makes the call.

Anyone extracting the key can decrypt this traffic.

Severity
Medium unwanted
Type
Unexpected
CWE
CWE-319
Source
Dynamic sandbox
What actually happens
You did this

You use an extension feature that reads Mercari item data or user information.

The extension's class ve (an API client) is instantiated when no local auth token is available in localStorage.

The extension did this

The extension encrypts Mercari API requests with a key hardcoded in the bundle and routes them through a developer-run Google Cloud Function instead of Mercari directly.

The AES ciphertext is placed in the x-parameters header of a POST to asia-northeast1-furima-assist-free.cloudfunctions.net/request.

The code that does this

AES encryption with hardcoded passphrase (content.js:50604-50628)

Readable version
class ve {  async request(e = {}) {    e.ts = (new Date).getTime();    const t = {      headers: {        "x-parameters": be.AES.encrypt(          JSON.stringify(e),          "_YOS+$'+U~iufw=$>t04HIhi(lB\"7x$v" // hardcoded AES passphrase        ).toString()      }    };    let r = {};    try {      const e = { options: t, type: "API" };      r = await a.a.runtime.sendMessage(e); // relay to background    } catch (e) {      console.log({ error: e })    }    return console.debug({ params: e, response: r }), r  }}
The code that does this

Service worker forwards the encrypted payload to the cloud function (background.js:1610-1621)

Readable version
const a = "https://asia-northeast1-furima-assist-free.cloudfunctions.net/request",  i = async e => {    console.log({ on: "apiRequest", endpoint: a, options: e });    const r = await fetch(a, { ...e, method: "post" });    return await r.text()  }
Reproduce it yourself

Demonstrates that the hardcoded AES passphrase in the extension bundle can decrypt any x-parameters header value captured from network traffic or server-side logs.

Requires
  • Node.js 16+
  • npm install crypto-js
decrypt-x-parameters.js · js
// Requires: npm install crypto-js// Usage: node decrypt-x-parameters.js '<base64-ciphertext>'// The ciphertext is the value of the x-parameters header from any proxied request.const CryptoJS = require('crypto-js');const HARDCODED_KEY = '_YOS+$\'+U~iufw=$>t04HIhi(lB"7x$v';const ciphertext = process.argv[2];if (!ciphertext) {  // Example: encrypt a sample payload to show round-trip  const sample = {    url: 'https://api.mercari.jp/items/get?id=m12345678&_item_photo_format=detail',    method: 'GET',    ts: Date.now()  };  const encrypted = CryptoJS.AES.encrypt(JSON.stringify(sample), HARDCODED_KEY).toString();  console.log('Sample encrypted x-parameters header value:');  console.log(encrypted);  console.log('\nDecrypted back:');  const decrypted = CryptoJS.AES.decrypt(encrypted, HARDCODED_KEY).toString(CryptoJS.enc.Utf8);  console.log(JSON.parse(decrypted));} else {  const decrypted = CryptoJS.AES.decrypt(ciphertext, HARDCODED_KEY).toString(CryptoJS.enc.Utf8);  console.log('Decrypted payload:');  console.log(JSON.parse(decrypted));}
How to run it
  1. 1Install dependency: npm install crypto-js.
  2. 2Run without arguments to see a sample round-trip: node decrypt-x-parameters.js.
  3. 3Pass a captured x-parameters header value to decrypt it: node decrypt-x-parameters.js '<base64-ciphertext>'.
Infrastructure receiving proxied Mercari API traffic
    • asia-northeast1-furima-assist-free.cloudfunctions.net

    Developer-run Google Cloud Function (project furima-assist-free). Receives proxied Mercari API requests, decrypts the x-parameters header, executes the call.

Where it sends data

Destinations our analysis observed フリマアシスト 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.

  • api.mercari.jp

    フリマアシスト sends data to api.mercari.jp. No other extension we have analysed sends data here.

  • asia-northeast1-furima-assist-free.cloudfunctions.net

    フリマアシスト sends data to asia-northeast1-furima-assist-free.cloudfunctions.net. No other extension we have analysed sends data here.

  • furima-assist.com

    フリマアシスト sends data to furima-assist.com. No other extension we have analysed sends data here.

  • kiyomaro.net

    フリマアシスト sends data to kiyomaro.net. No other extension we have analysed sends data here.

Updated 30 September 2026jcbljdgnpcckiamdgmnfhijgkkaogmgg