Is PoshPop | Poshmark Closet Bot safe?

High risk

PoshPop | Poshmark Closet Bot can forward Poshmark cookies and request headers to poshpoptools.com in error logs.

When some Poshmark API requests fail, the extension's error logging path can include request headers, including Poshmark cookies, in a message sent to its remote iframe at poshpoptools.com. It also sets a Chrome uninstall feedback URL that includes the authenticated user's email address when Chrome opens the Tally form after uninstall.

https://poshpopassistant.com/v4.10.0Chrome Web Store
72Risk
Who publishes it

https://poshpopassistant.com/ - no other listings under this identity

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

Publisher
https://poshpopassistant.com/
Registered address
604 BANYAN TRL # 812051, BOCA RATON, FL 33481, United States

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

Publishers can request a review.

Findings

Cookie headers can reach PoshPop iframe logs

Starting a Poshmark sharing action makes the extension create API requests with page cookies in the headers.

A failed 400-series request has its headers copied into a log, forwarded to the PoshPop iframe at https://poshpoptools.com/.

Severity
High unwanted
Type
Unexpected
CWE
CWE-522
Source
Dynamic sandbox
What actually happens
You did this

You start a Poshmark sharing action from the PoshPop sidebar.

The extension did this

If a handled Poshmark request failure occurs, the extension can copy request headers, including cookies, into a log sent to the PoshPop iframe.

Fields copied into the error log context
  • Your Poshmark cookies
    cookie: ui=us; jwt2=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 (illustrative)

    These values can identify your signed-in Poshmark session when they are copied from the page into a request header.

  • The Poshmark API URL
    URL: https://poshmark.com/vm-rest/users/self/shared_posts/123456789 (illustrative)

    This shows which Poshmark action failed and can reveal the item or sharing workflow tied to your account activity.

  • Request method and headers
    Method: PUT; Headers: accept, content-type, cookie (illustrative)

    The log records the request method and every header name and value that the failed request carried.

  • Log message type
    type: EXTENSION_LOG; level: error

    This identifies the message as an extension log sent to the remote iframe rather than a local-only browser console entry.

Captured request
GEThttps://poshpoptools.com/

The content script loads this host as the PoshPop iframe; the cookie-bearing log is then delivered to that iframe with postMessage. No HTTP request body was recorded for this claim.

The code that does this

The request, logging, and iframe paths in the shipped extension

Readable version

Source map: Share.editShareAPICall and Share.normalShareAPICall

src/classes/Share.ts
	async editShareAPICall(currentItem: ProductReturnedInfo): Promise<void> {		log("Sharing API Call")		const request = new Request(productDetailsURL + currentItem?.id, {			method: "POST",			headers: {				Accept: "application/json",				"content-type": "application/json",				cookie: document.cookie			},			body: JSON.stringify(currentItem)		})		const response = await fetch(request)		if (!response.ok) {			if ((response.status >= 500 && response.status < 600) || response.status === 403)				throw new NotReportableException("Failed to connect to Poshmark")			throw new RequestException(				`Error: ${response.statusText} status: ${response.status}`,				request,				response			)		}		const jsonRes = await response.json()		//poshmark returned error		if (jsonRes.error) {			this.poshmarkErrorHandler(jsonRes)		}	}	/**	 * Description placeholder	 *	 * @async	 * @param {ProductReturnedInfo} currentItem	 * @returns {Promise<void>}	 */	async normalShareAPICall(currentItem: ProductReturnedInfo): Promise<void> {		const request = new Request(this.sharingApi + currentItem?.id, {			method: "PUT",			headers: {				Accept: "application/json",				"content-type": "application/json",				cookie: document.cookie			}		})		const response = await fetch(request)		if (!response.ok) {			if ((response.status >= 500 && response.status < 600) || response.status === 403)				throw new NotReportableException("Failed to connect to Poshmark")			throw new RequestException(				`Error: ${response.statusText} status: ${response.status}`,				request,				response			)		}		const jsonRes = await response.json()		//poshmark returned error		if (jsonRes.error) {			this.poshmarkErrorHandler(jsonRes)		}	}

Source map: sendLogToWebsite and ExtensionLogger

src/utilities/logExtension.ts
function sendLogToWebsite(logDetails: LogMessage): void {	try {		const poshmarkStore = userPoshmarkUserStore()		const payload = {			type: "EXTENSION_LOG",			log: {				//TODO: Context invalidation , store version beforehand in global index like the other data				version: EXTENSION_VERSION,				country: getCountry(),				...logDetails,				context: logDetails.context,				store: poshmarkStore.username.value			},			timestamp: new Date().toISOString()		}		sendWindowMessage(payload)	} catch (e) {		console.error("Failed to send log to website:", e)	}}/** * Wrapper for logging extension events. */export const ExtensionLogger = {	info: (message: string, context?: any) => sendLogToWebsite({ level: "info", message, context }),	warn: (message: string, context?: any) => sendLogToWebsite({ level: "warn", message, context }),	error: (message: string, context?: any) =>		sendLogToWebsite({ level: "error", message, context }),	debug: (message: string, context?: any) =>		sendLogToWebsite({ level: "debug", message, context })}

Source map: convertArgsToTruncatedText

src/utilities/index.ts
function convertArgsToTruncatedText(args: any[]): string {	const lines: string[] = []	for (const arg of args) {		if (typeof arg === "string") {			lines.push(arg)		} else if (arg instanceof Error) {			if (				arg instanceof NotReportableException ||				(arg instanceof UserActivityException && !arg.isReportable)			)				continue			// Use stack trace for Errors			lines.push(arg.stack || arg.toString())			if (arg instanceof RequestException) {				const { request, response, requestPayload } = arg				// Log Request Metadata				lines.push("--- Request Details ---")				lines.push(`URL: ${request.url}`)				lines.push(`Method: ${request.method}`)				// Log Request Headers				lines.push("Headers:")				request.headers.forEach((value, name) => {					lines.push(`  ${name}: ${value}`)				})				if (requestPayload) {					lines.push("\nRequest Payload (Body):")					lines.push(JSON.stringify(requestPayload, null, 2))				}				lines.push("--- Response Details ---")				lines.push(`Status: ${response.status} ${response.statusText}`)				lines.push(`Content-Type: ${response.headers.get("content-type") || "N/A"}`)				// Log Response Headers				lines.push("Headers:")				response.headers.forEach((value, name) => {					lines.push(`  ${name}: ${value}`)				})			}		} else {			// Use JSON.stringify with the replacer for everything else			try {				// The replacer handles truncation before stringification				lines.push(JSON.stringify(arg, truncatingReplacer, 2))			} catch (e) {				// Fallback for objects with circular references				lines.push(`[Object failed to stringify: ${String(e)}]`)			}		}	}	return lines.join("\n")}

Source map: sendWindowMessage

src/utilities/index.ts
export const sendWindowMessage = (data: any) => {	const iframe = document?.getElementById(POSHPOP_SIDEBAR_ID) as HTMLIFrameElement	iframe?.contentWindow?.postMessage(data, "*")}

Source map: iframe creation and remote URL constant

src/view/PoshPopApp.vue and src/constants/environment.ts
const initAndLoadIframe = async () => {    if (isInitalized.value) return    //Embedding iframe dynamically to load website in previously opened tab. Doesn't load it otherwise    const iframe = document.createElement("iframe")    iframe.setAttribute("src", remoteServerURL + '?timestamp=' + new Date().getTime() + "&version=" + manifestData.version + "&origin=" + window.location.origin)    iframe.setAttribute("name", String(Date.now()))    iframe.setAttribute("id", POSHPOP_SIDEBAR_ID)    iframe.style.position = "relative"    iframe.style.zIndex = '2'    iframe.setAttribute("allow", "clipboard-read; clipboard-write")    iframe.onload = initializePoshpopAndMessageListeners    sidePanelRef.value.append(iframe)    isInitalized.value = true;}export const remoteServerURL = process.env.VUE_APP_WEB_UI_SERVER_URL ?? ""export const serverUrl = process.env.VUE_APP_SERVER_URL ?? ""
Hosts involved in the error-log path
    • poshpoptools.com

    Hosts the PoshPop iframe that receives EXTENSION_LOG messages via postMessage.

    • poshmark.com

    Receives the original sharing API request whose headers are copied into the error log after certain failures.

Where it sends data

Destinations our analysis observed PoshPop | Poshmark Closet Bot 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.

  • poshpoptools.com

    PoshPop | Poshmark Closet Bot sends data to poshpoptools.com. No other extension we have analysed sends data here.

  • tally.so

    PoshPop | Poshmark Closet Bot sends data to tally.so. No other extension we have analysed sends data here.

Updated 30 September 2026fehkmdemphhohcbggclooebcggikmodo