Is Google Translate Assistant – Side-by-side Translation | PDF Translation safe?

Medium risk

Google Translate Assistant sends page URLs, device identifiers, and tab screenshots to its vendor servers during normal use.

On every user action and daily check-in, the extension transmits a persistent device UUID, user ID, IP country code, and OS fingerprint to translate-useraction-api.xiangtatech.com. When auto-translate is checked for a page, the full URL of that page is sent to translate-api.xiangtatech.com to determine eligibility. If the user invokes the OCR translate feature, a screenshot of the visible tab is captured and uploaded to the same vendor server for processing.

轻主页v1.2.0.3Chrome Web Store
49Risk
Who publishes it

轻主页 - 3 other listings 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
轻主页

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

translate-cdn.kangaroooffice.com
Also called by 6 other listings
translate-cdn.xiangtatech.com
Also called by 6 other listings
translate-useraction-api.xiangtatech.com
Also called by 6 other listings
translate-api.kangaroooffice.com
Also called by 7 other listings, including Online Translator - Web Page|PDF| Bilingual Subtitles, Google Translate Assistant, 网页翻译 - PDF双语对照 |极速翻译 | 划词翻译
translate-api.xiangtatech.com
Also called by 7 other listings, including 北极象沉浸式翻译 - 沉浸式翻译 | 免费翻译 | PDF翻译, 划词翻译 - 网页划词翻译 | 沙拉词典 | 网络翻译器, 网页翻译 - PDF双语对照 |极速翻译 | 划词翻译
threejs-journey.com
Also called by 8 other listings, including 网页翻译 - PDF双语对照 |极速翻译 | 划词翻译
cr-fykz.kangaroooffice.com
Also called by 9 other listings
egghead.io
Also called by 9 other listings
frontendmasters.com
Also called by 9 other listings
home.mindvalley.com
Also called by 9 other listings
usercenter-pay.xiangtatech.com
Also called by 9 other listings, including 网页翻译 - PDF双语对照 |极速翻译 | 划词翻译

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

Publishers can request a review.

Findings

OCR translation uploads selected page images

MediumunwantedCWE-200Dynamic sandbox

OCR translation captures the visible tab as a PNG for cropping.

What actually happens

You did this

You start screenshot translation and confirm a cropped region of the current page.

The extension did this

The extension captures the visible tab, converts your selected crop into a PNG file, and sends it for picture translation.

Multipart fields prepared for picture translation

  • Selected page image
    image.png from the selected crop

    Sends the visible text and graphics inside the crop you confirm.

  • Source language
    from auto

    Tells the translation service which language the selected image starts from.

  • Target language
    to en

    Tells the translation service which language to translate into.

  • Page range markers
    start_page -1, end_page -1

    Adds fixed page-range fields even though the upload is a screenshot image.

Captured request

POSThttps://translate-api.xiangtatech.com/translate/translation/webs/picture

Source-code proof: the shipped code posts multipart form data containing file, from, to, start_page, and end_page. The runtime test recorded no request to this endpoint.

The code that does this

The screenshot path captures the tab and uploads the cropped image

Readable version

assets/background.js beautified screenshot case

assets/background.js
                case "screenshot":                    chrome.tabs.captureVisibleTab(t.tab.windowId, {                        format: "png"                    }, (e => n(e)));                    break;

assets/main6.js beautified screenshot methods

assets/main6.js
            enter() {                this.captureing || (this.captureing = !0, chrome.runtime.sendMessage({                    type: "screenshot"                }, (e => {                    this.bodyOverflow = document.documentElement.style.overflow, document.documentElement.style.overflow = "hidden", document.addEventListener("keydown", this.onKeydown_), this.imgURL = e, this.isShow = !0                })))            },            confirm() {                if (!this.cropper) return this.cancel();                const e = {                    from: this.sourceItem.gid,                    to: this.targetItem.gid                };                this.cropper.getCroppedCanvas().toBlob((t => {                    this.cancel(), this.$emit("confirm", t, e)                }))            }

assets/main6.js beautified OCR upload method

assets/main6.js
            ocr(e, t) {                var n, o;                if (this.loading) return void eo(this.$t("ocr.loading"), {                    appendToEl: this.$refs.box                });                if (!e && !this.ocrBlob) return;                this.initOriginImg(e || this.ocrBlob), t && (t.from && (null == (n = this.$refs.switchLangRef) || n.setSourceLang(t.from)), t.to && (null == (o = this.$refs.switchLangRef) || o.setTargetLang(t.to))), this.showSceneCoupon = !1, e ? this.ocrBlob = e : e = this.ocrBlob;                const a = new FormData,                    i = new File([e], "image.png", {                        type: e.type                    });                a.append("file", i), a.append("from", this.sourceItem.gid), a.append("to", this.targetItem.gid), a.append("start_page", -1), a.append("end_page", -1), ao({                    url: "https://translate-api.xiangtatech.com/translate/translation/webs/picture",                    type: "post",                    formData: a,                    dataType: "json",                    success: e => {                        var t, n;                        e.data ? (this.clearTransData(), this.loading = !0, this.queryTaskTime(null == (t = e.data) ? void 0 : t.file_translation_id), this.isShow = !0, this.currentTaskId = null == (n = e.data) ? void 0 : n.file_translation_id) : (this.ocrError(e.msg || this.$t("ocr.noText")), this.showErrorDialog = !0)                    },                    error: e => {                        var t, n;                        1011 !== (null == (t = e.response) ? void 0 : t.code) ? 406 !== (null == (n = e.response) ? void 0 : n.code) ? (this.ocrError(e.response && (e.response.msg || e.response.message) || this.$t("ocr.fail"), e.response && e.response.code || e.status), this.showErrorDialog = !0) : eo(this.$t("ocr.notSupportedFile")) : eo(this.$t("ocr.loading"), {                            appendToEl: this.$refs.box                        })                    }                })            },

assets/main6.js beautified OCR entry point

assets/main6.js
            startOcrTranslate(e) {                return c(this, null, (function*() {                    if (yield this.closeOpenedFunDialog(), !this.canScreenshot) return;                    this.inScreenshot = !0, setTimeout((() => {                        this.$refs.screenshotTool.enter()                    }), 24);                    const t = {                        param15: "default"                    };                    e && Object.assign(t, e), this.$mergeSubmitReport({                        event_id: 107,                        extend_fields: t                    })                }))            },            onScreenshotConfirm(e, t) {                return c(this, null, (function*() {                    var n;                    this.inScreenshot = !1, null == (n = this.$refs.imageTranslate) || n.close((() => {                        var n;                        null == (n = this.$refs.ocrTranslate) || n.ocr(e, t)                    }))                }))            },

Picture-translation destination

    • translate-api.xiangtatech.com

    Vendor picture-translation endpoint that receives the cropped screenshot image form.

Persistent browser identifiers sent in action reports

MediumunwantedCWE-359Dynamic sandbox

The extension posts a user-action report with a persistent browser-ID prefix, OS values, event IDs, and IP-country context to translate-api.kangaroooffice.com.

What actually happens

You did this

You browse or use extension features while Google Translate Assistant is active.

The extension did this

The extension builds a user-action report with a persistent browser identifier, device details, event IDs, and account fields when available.

Captured request

POSThttps://translate-api.kangaroooffice.com/useraction/api/v2/report

Observed during dynamic analysis: pcid beginning fe13fa8a, os_version 41658296553177090, os_type 1, event_id 1, extend_fields param10=美国; repeated reports used event IDs 100, 101, and 243.

Headers
Content-Type
application/json

Fields assembled for the user-action report

  • Persistent browser identifier
    pcid beginning fe13fa8a

    Lets the reporting service connect separate reports from the same browser over time.

  • Account identifier when signed in
    user_id 92837465 (illustrative)

    Links the report to the extension account if account data is stored locally.

  • IP-country context
    美国

    Adds the country associated with your network location to the report.

  • Operating system details
    os_type 1, os_version 41658296553177090

    Adds device context that helps distinguish browsers and environments.

  • Extension event IDs
    event_id 1, 100, 101, or 243

    Shows which extension action or scheduled check produced the report.

The code that does this

The shipped report builders read storage fields and post the report

Readable version

assets/browser.js beautified function mu

assets/browser.js
function mu(e) {    chrome.storage.local.get(["uuid", "token", "loginRegion", "loginType", "userInfo", "lastRefreshUserInfoTime", "ipCountry", "extShareUnionId", "reportAgree"], (({        uuid: t,        token: n,        loginRegion: a,        loginType: r,        userInfo: i,        lastRefreshUserInfoTime: o,        ipCountry: s,        extShareUnionId: l,        reportAgree: c    }) => {        t = (t = t || "").length > 32 ? t.slice(0, 32) : t.padStart(32, "0");        const _ = f({                token: n,                ipCountry: s,                loginRegion: a            }),            d = {                bs: "bs",                sub_module: "TranslateAssistant",                appid: Number("US" === _ ? "132" : "113"),                unionid: Number(l) || Number("3000") || 1,                version: gu("1.2.0.2"),                pcid: t,                os_version: gu(Eu().version),                arch: 65535,                os_type: "mac" === bu() ? 5 : 1,                events: []            },            p = {                c_timestamp: Math.round(Date.now() / 1e3),                extend_fields: {                    scene: 300,                    param13: "3000"                }            };        if (s && (p.extend_fields.param10 = s), n && (p.extend_fields.param11 = (r || "wx") + "Login", null == i ? void 0 : i.user_id)) {            if (p.extend_fields.user_id = i.user_id + "", o && i.buy_right_package) {                const e = new Date - o;                e > 0 && (i.server_time += Math.round(e / 1e3), i.is_member = i.buy_right_package.some((e => e.unlimited || new Date(e.expire_at).getTime() / 1e3 > i.server_time)))            }            p.extend_fields.param1 = i.is_member ? 1 : 0        }        e.forEach((([e]) => {            var t, a;            "string" != typeof e && "number" != typeof e || (e = {                event_id: Number(e)            });            const r = Ap({}, p);            129 === e.event_id && n && (null == (a = null == (t = null == i ? void 0 : i.buy_right_package) ? void 0 : t[0]) ? void 0 : a.buy_time) && (r.extend_fields.param12 = i.buy_right_package[0].buy_time), e = Ap(r, e), d.events.push(e)        })), jp({            url: "https://translate-useraction-api.xiangtatech.com/api/v2/report",            type: "post",            noAppId: !0,            noToken: !0,            headers: {                "Content-Type": "application/json",                "Sign-Type": 0,                Business: "TranslateAssistant"            },            data: d,            success() {                e && e.forEach((([, e]) => {                    "function" == typeof(null == e ? void 0 : e.success) && e.success()                })), e = null            },            error() {                e && e.forEach((([, e]) => {                    "function" == typeof(null == e ? void 0 : e.error) && e.error()                })), e = null            }        })    }))}

js/content-start.js beautified function Rp

js/content-start.js
    function Rp(e) {        chrome.storage.local.get(["uuid", "token", "loginRegion", "loginType", "userInfo", "lastRefreshUserInfoTime", "ipCountry", "extShareUnionId", "reportAgree"], (({            uuid: t,            token: n,            loginRegion: a,            loginType: r,            userInfo: i,            lastRefreshUserInfoTime: o,            ipCountry: s,            extShareUnionId: l,            reportAgree: c        }) => {            t = (t = t || "").length > 32 ? t.slice(0, 32) : t.padStart(32, "0");            const _ = Ep({                    token: n,                    ipCountry: s,                    loginRegion: a                }),                d = {                    bs: "bs",                    sub_module: "TranslateAssistant",                    appid: Number("US" === _ ? "132" : "113"),                    unionid: Number(l) || Number("3000") || 1,                    version: vp("1.2.0.2"),                    pcid: t,                    os_version: vp(Np().version),                    arch: 65535,                    os_type: "mac" === yp() ? 5 : 1,                    events: []                },                p = {                    c_timestamp: Math.round(Date.now() / 1e3),                    extend_fields: {                        scene: 300,                        param13: "3000"                    }                };            if (s && (p.extend_fields.param10 = s), n && (p.extend_fields.param11 = (r || "wx") + "Login", null == i ? void 0 : i.user_id)) {                if (p.extend_fields.user_id = i.user_id + "", o && i.buy_right_package) {                    const e = new Date - o;                    e > 0 && (i.server_time += Math.round(e / 1e3), i.is_member = i.buy_right_package.some((e => e.unlimited || new Date(e.expire_at).getTime() / 1e3 > i.server_time)))                }                p.extend_fields.param1 = i.is_member ? 1 : 0            }            e.forEach((([e]) => {                var t, a;                "string" != typeof e && "number" != typeof e || (e = {                    event_id: Number(e)                });                const r = _p({}, p);                129 === e.event_id && n && (null == (a = null == (t = null == i ? void 0 : i.buy_right_package) ? void 0 : t[0]) ? void 0 : a.buy_time) && (r.extend_fields.param12 = i.buy_right_package[0].buy_time), e = _p(r, e), d.events.push(e)            })), Tp({                url: "https://translate-useraction-api.xiangtatech.com/api/v2/report",                type: "post",                noAppId: !0,                noToken: !0,                headers: {                    "Content-Type": "application/json",                    "Sign-Type": 0,                    Business: "TranslateAssistant"                },                data: d,                success() {                    e && e.forEach((([, e]) => {                        "function" == typeof(null == e ? void 0 : e.success) && e.success()                    })), e = null                },                error() {                    e && e.forEach((([, e]) => {                        "function" == typeof(null == e ? void 0 : e.error) && e.error()                    })), e = null                }            })        }))    }

Reporting hosts named by evidence and source code

    • translate-api.kangaroooffice.com

    Observed vendor user-action report destination during dynamic analysis.

    • translate-useraction-api.xiangtatech.com

    User-action report host hardcoded in the shipped reporting functions.

Where it sends data

Destinations our analysis observed Google Translate Assistant – Side-by-side Translation | PDF Translation 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.

  • translate-api.xiangtatech.com

    Google Translate Assistant – Side-by-side Translation | PDF Translation sends data to translate-api.xiangtatech.com. 2 other extensions we have analyzed send data here.

  • translate-useraction-api.xiangtatech.com

    Google Translate Assistant – Side-by-side Translation | PDF Translation sends data to translate-useraction-api.xiangtatech.com. No other extension we have analyzed sends data here.

Updated 30 September 2026fjkpgkefceopkogemcjcnncdhbgldolm