Is Fable: Create step-by-step interactive demos and guides in 5 minutes. safe?
Fable: Create step-by-step interactive demos and guides in 5 minutes. is high risk. After Stop Recording is clicked, the extension opens app.sharefable.com/preptour and sends it your available cookies, written into the page's IndexedDB.…
Who publishes itPyxis Voyager Inc. - no other listings under this identity
Pyxis Voyager Inc. - no other listings under this identity
What this publisher told the store about itself, and the other listings that told it the same thing.
AI-generated. Findings may contain errors. Those marked Verified have been manually reviewed.
Publishers can request a review.
Findings
Recording handoff copies browser cookies to Fable storage
After Stop Recording is clicked, the extension opens app.sharefable.com/preptour and sends it your available cookies, written into the page's IndexedDB. getAll runs with no domain/URL filter, so session/auth cookies may be included.
- Severity
- High unwanted
- Type
- Unexpected
- CWE
- CWE-522
- Source
- Dynamic sandbox
You stop and submit a demo recording from the extension popup.
The popup sends the service worker the extension's Stop Recording message.
The extension reads browser cookies and copies them into the Fable app page's local storage.
The cookie array is sent to the preptour tab, where the app-page script saves it in IndexedDB.
- Cookie name and valuesessionid=8f14e45fceea167a5a36dedd4bea2543 (illustrative)
Can carry session or login state for a site. If a value is reusable, it may identify a signed-in session.
- Cookie domain.example-corp.com (illustrative)
Shows which site set the cookie and ties the value to that service.
- Security flagssecure=true; httpOnly=true; sameSite=lax (illustrative)
Shows whether the cookie was marked for HTTPS-only use or blocked from page scripts, even though the extension API can read it.
- Browser cookie storestoreId=0; expirationDate=1794686400 (illustrative)
Shows which browser profile store held the cookie and whether the value is persistent.
The source opens this page for the recording handoff; no request body was recorded in the available evidence.
This is the app-page record shape where the handoff stores the serialized cookie array alongside recording data.
- Location
- app.sharefable.com IndexedDB screensDB/screensDataStore key 1
{ "id": "1", "cookies": "JSON.stringify(cookiesData)", "version": "3", "screensData": "JSON.stringify(screensData)", "screenStyleData": "JSON.stringify(styleData)"}Cookie read, handoff message, and IndexedDB write
Readable equivalent of the cookie reader
background.jsasync function getAllCookies() { let cookies = []; let hasErr = false; try { cookies = await chrome.cookies.getAll({ partitionKey: {} }); } catch (err) { hasErr = true; sentryCaptureException(err); } if (hasErr || cookies.length === 0) { cookies = await chrome.cookies.getAll({}); } return cookies;}Readable equivalent of the handoff branch
background.jsasync function handleClientContentInit(sender) { if (!sender.tab) { return; } const data = await chrome.storage.local.get(SCREEN_DATA_FINISHED); const cookies = await getAllCookies(); const screenStyleData = (await chrome.storage.local.get(SCREEN_STYLE_DATA))[SCREEN_STYLE_DATA] || {}; await chrome.tabs.sendMessage(sender.tab.id, { type: Msg.SAVE_TOTAL_SCREEN_COUNT_IN_EXCHANGE_DIV, data: { totalScreenCount: data[SCREEN_DATA_FINISHED].length ?? 0 } }); for (let i = 0; i < data[SCREEN_DATA_FINISHED].length; i += BATCH_SIZE) { await chrome.tabs.sendMessage(sender.tab.id, { type: Msg.SAVE_SCREENS_DATA_IN_EXCHANGE_DIV, data: { screensData: data[SCREEN_DATA_FINISHED].slice(i, i + BATCH_SIZE) || [] } }); } await chrome.tabs.sendMessage(sender.tab.id, { type: Msg.SAVE_COOKIES_DATA_IN_EXCHANGE_DIV, data: { cookiesData: cookies } }); await chrome.tabs.sendMessage(sender.tab.id, { type: Msg.SAVE_STYLE_DATA, data: { screenStyleData } }); await chrome.tabs.sendMessage(sender.tab.id, { type: Msg.SAVE_VERSION_DATA, data: { version: "3" } }); await chrome.tabs.sendMessage(sender.tab.id, { type: Msg.SAVE_TOUR_DATA }); await chrome.storage.local.remove(SCREEN_DATA_FINISHED); await chrome.storage.local.remove(SCREEN_STYLE_DATA);}Readable equivalent of the app-page storage write
client_content.jsasync function maybeWriteHandoffData(message) { if (message.type === Msg.SAVE_COOKIES_DATA_IN_EXCHANGE_DIV) { cookiesData = message.data.cookiesData; cookiesDataReceived = true; } if (styleDataReceived && cookiesDataReceived && commitReceived && versionReceived) { setTimeout(async function () { const db = await openDb(DB_NAME, OBJECT_STORE, 1, OBJECT_KEY); const dbData = { id: OBJECT_KEY_VALUE, screensData: JSON.stringify(screensData), cookies: JSON.stringify(cookiesData), screenStyleData: JSON.stringify(styleData), version: dataVersion }; if (screensData.length) { await putDataInDb(db, "screensDataStore", dbData); } db.close(); document.body.appendChild(createOrUpdateRedirectReadyDiv(1)); }, 500); }}What it can do
Permissions this extension asks for, as declared in version 2.1.7. Asking for a permission is not a finding on its own - it is what the extension can do if it chooses to.
Read and change your data on every site you visit
<all_urls> and 1 more
See the address and title of every tab you have open
tabs
Run its own code inside the pages you visit
scripting
Store data in your browser
storage
See every page you navigate to, as you navigate to it
webNavigation
Read and change cookies, including the ones that keep you signed in
cookies
Store an unlimited amount of data in your browser
unlimitedStorage