Is YouTube Dubbing – Translate & Dub safe?

Medium risk

YouTube Dubbing is medium risk. Active on Facebook, the background worker captures x-fb-lsd (CSRF token) and x-asbd-id (session ID), replays your GraphQL body with credentials:include so session cookies attach. DA observed four replays returning 200 within 140-300ms.…

zhiboli597v4.3.19Chrome Web Store
49Risk
Who publishes it

zhiboli597 - no other listings under this identity, 5 shared hostnames

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

Publisher
zhiboli597

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

youtube-dubbing-1251726835.cos.ap-singapore.myqcloud.com
Also called by 2 other listings, including youtube中文配音
youtube-dubbing.com
Also called by 2 other listings, including youtube中文配音
mylearn.oracle.com
Also called by 3 other listings, including youtube中文配音
yd.transduck.com
Also called by 3 other listings, including youtube中文配音
kinescope.io
Also called by 5 other listings, including ANNEXX, CodeMP - Автоматизация Wildberries

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

Publishers can request a review.

Findings

Facebook Session Reuse via Captured Auth Headers

Active on Facebook, the background worker captures x-fb-lsd (CSRF token) and x-asbd-id (session ID), replays your GraphQL body with credentials:include so session cookies attach.

DA observed four replays returning 200 within 140-300ms.

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

You open a Facebook page that contains a video while the extension is installed.

Your browser sends authenticated GraphQL requests to facebook.com/api/graphql to fetch video data.

The extension did this

The extension captures your Facebook CSRF and session-binding headers, then replays the same GraphQL POST body with your session cookies included.

Dynamic analysis observed four such replay requests, each arriving within 140-300 ms of the original browser request and each returning HTTP 200 OK.

Facebook authentication headers captured and replayed by the extension
  • CSRF token
    x-fb-lsd: AJzBk7mG2nQ4p

    Facebook's per-session request-validation token. Passing it lets the replay be accepted as if from your browser tab.

  • Session binding ID
    x-asbd-id: 129477

    An internal Facebook ID tying a request to an app session. The extension passes it unchanged to authenticate the GraphQL call.

  • GraphQL operation name
    x-fb-friendly-name: UnifiedVideoRootQuery

    Identifies which Facebook GraphQL operation is being replayed, typically video-related queries such as timeline feed or video root fetches.

  • Session cookies (browser-attached)
    Cookie: c_user=100012345678901; xs=<session-token>

    With credentials:include, Facebook cookies attach via the browser. The extension doesn't capture them directly, but they're in the replay.

The code that does this

Header interception, filtering, and GraphQL replay (background.js)

Readable version

captureAuthHeaders — collects all x-* headers from intercepted Facebook requests

captureAuthHeaders(requestHeaders) {  const captured = {};  if (!requestHeaders) return captured;  for (const header of requestHeaders) {    const name = header.name.toLowerCase();    // Collects every x-* header plus Authorization and Content-Type    if ((name.startsWith('x-') || name === 'authorization' || name === 'content-type') && header.value) {      captured[header.name] = header.value;    }  }  return captured;  // Example result: { 'x-fb-lsd': 'AJzBk7mG2nQ4p', 'x-asbd-id': '129477',  //                   'x-fb-friendly-name': 'UnifiedVideoRootQuery', 'content-type': 'application/x-www-form-urlencoded' }}

fetchAndStoreFacebookMappings — replays the captured POST body using the user's live Facebook session

async fetchAndStoreFacebookMappings(tabId, originalUrl, originalBody, capturedHeaders) {  if (!originalBody) return;  // Filter the captured headers to only the four allowlisted values  const replayHeaders = this.buildFacebookReplayHeaders(capturedHeaders);  // FACEBOOK_REPLAY_HEADER_ALLOWLIST = ['content-type','x-fb-friendly-name','x-fb-lsd','x-asbd-id']  // POST the original GraphQL body back to Facebook with credentials: include  // The browser attaches the user's active Facebook session cookies automatically  const response = await fetch(originalUrl, {    method:      'POST',    headers:     replayHeaders,    body:        originalBody,    credentials: 'include'   // <-- causes browser to attach Facebook login cookies  });  const responseText = await response.text();  const jsonLines    = parseNewlineDelimitedJson(responseText);  const mappings     = this.extractFacebookMappingsFromUnits(jsonLines);  if (!response.ok && mappings.length === 0) return;  if (mappings.length === 0) return;  // Store video stream URLs for use by the dubbing feature  await this.storeFacebookMappings(mappings);}
Captured request
POSThttps://www.facebook.com/api/graphql/

HTTP 200 OK. Response contains video stream metadata including available dubbing locales and DASH manifest URLs. Four such responses were observed during dynamic analysis, with body sizes of 2,386, 2,624, 4,212, and 2,565 bytes.

Headers
x-fb-lsd
AJzBk7mG2nQ4p
x-asbd-id
129477
content-type
application/x-www-form-urlencoded
x-fb-friendly-name
UnifiedVideoRootQuery
Body
av=0&__user=0&__a=1&__req=k&__ccg=GOOD&__rev=1018344102&fb_api_req_friendly_name=UnifiedVideoRootQuery&variables=%7B%22videoID%22%3A%221234567890123456%22%7D&server_timestamps=true&doc_id=7291034567890123
External hosts contacted in this flow
    • www.facebook.com

    Destination for the GraphQL replay requests. The extension POSTs to /api/graphql/ using the user's active session to fetch video mapping data. Operated by Meta Platforms, Inc.

    • fbcdn.net

    Facebook's CDN for media. The extension also intercepts *.fbcdn.net to capture auth headers via the same listener. Operated by Meta.

Hardcoded Microsoft Translator HMAC Signing Key

YouTube Dubbing embeds a hardcoded HMAC-SHA256 key and app-identity string, taken from Microsoft Translator's Android app.

Dubbing signs a request for a short-lived Azure JWT authorizing TTS calls.

The key sits as plain base64 in source.

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

You activate the dubbing feature on any page.

The extension needs Azure text-to-speech credentials to synthesize dubbed audio.

The extension did this

The background script uses a hardcoded HMAC key to sign a request that impersonates the Microsoft Translator Android app, then exchanges that signature for an Azure TTS JWT.

The signed POST goes to dev.microsofttranslator.com/apps/endpoint; the returned JWT authorizes subsequent calls to *.tts.speech.microsoft.com/cognitiveservices/v1.

Hardcoded credentials embedded in background.js (lines 9009-9019)
  • HMAC signing key
    oik6PdDdMnOXemTbwvMn9de/h9lFnfBaCWbGMMZqqoSaQaqUOqjVGm5NqsmjcBI1x+sS9ugjB55HEJWRiFXYFw==

    A base64 key producing signatures Microsoft's endpoint accepts. Anyone who extracts it can generate valid tokens without the extension.

  • Impersonated app identity
    MSTranslatorAndroidApp

    The identity string the extension presents to Microsoft's server, matching the registered Microsoft Translator Android app.

  • Spoofed client version
    4.0.530a 5fe1dc6c

    The extension reports itself as a specific Microsoft Translator Android release in the X-ClientVersion header of every token request.

  • Hardcoded user ID
    0f04d16a175c411e

    A fixed account identifier sent in every token request. All 200,000 extension users share this same identifier.

The code that does this

HMAC signature construction and Azure token fetch (background.js)

Readable version

Hardcoded credentials — the signing material

const EDGE_AZURE_TTS_CONFIG = {  SIGNATURE_APP_ID: 'MSTranslatorAndroidApp',     // Identity to impersonate  SIGNATURE_SECRET_BASE64: 'oik6PdDdMnOXemTbwvMn9de/h9lFnfBaCWbGMMZqqoSaQaqUOqjVGm5NqsmjcBI1x+sS9ugjB55HEJWRiFXYFw==',  // HMAC-SHA256 key  ENDPOINT_URL: 'https://dev.microsofttranslator.com/apps/endpoint?api-version=1.0',  USER_AGENT: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0',  CLIENT_VERSION: '4.0.530a 5fe1dc6c',            // Spoofed Android app version  USER_ID: '0f04d16a175c411e',                    // Fixed identifier shared by all installs  HOME_REGION: 'zh-Hans-CN',  OUTPUT_FORMAT: 'audio-24khz-48kbitrate-mono-mp3'};

buildSignature — derives the X-MT-Signature header from the hardcoded key

async function buildSignature(endpointUrl = CONFIG.ENDPOINT_URL, now = new Date()) {  // Construct the plaintext message to sign  const encodedPath   = encodeURIComponent(endpointUrl.split('://')[1] ?? '');  const requestId     = crypto.randomUUID().replace(/-/g, '');  const formattedDate = toRFC1123(now);  const plaintext     = (CONFIG.SIGNATURE_APP_ID + encodedPath + formattedDate + requestId).toLowerCase();  // Decode the hardcoded base64 key and compute HMAC-SHA256  const keyBytes  = base64ToUint8Array(CONFIG.SIGNATURE_SECRET_BASE64);  const hmacKey   = await crypto.subtle.importKey('raw', keyBytes, { name: 'HMAC', hash: 'SHA-256' }, false, ['sign']);  const hmacBytes = await crypto.subtle.sign('HMAC', hmacKey, new TextEncoder().encode(plaintext));  return {    signature: `${CONFIG.SIGNATURE_APP_ID}::${uint8ArrayToBase64(hmacBytes)}::${formattedDate}::${requestId}`,    requestId  };}

fetchEndpointToken — exchanges the signature for an Azure Cognitive Services JWT

async function fetchEndpointToken(date, signal) {  const { signature, requestId } = await buildSignature(CONFIG.ENDPOINT_URL, date);  return fetch(CONFIG.ENDPOINT_URL, {    method: 'POST',    headers: {      'Accept-Language':          'zh-Hans',      'X-ClientVersion':          CONFIG.CLIENT_VERSION,   // '4.0.530a 5fe1dc6c'      'X-UserId':                 CONFIG.USER_ID,          // '0f04d16a175c411e'      'X-HomeGeographicRegion':   CONFIG.HOME_REGION,      'X-ClientTraceId':          requestId,      'X-MT-Signature':           signature,               // HMAC-signed with hardcoded key      'Content-Type':             'application/json; charset=utf-8'    },    body: '',    signal  });  // Response: { t: '<JWT>', r: '<azure-resource-id>' }  // JWT is then used as Authorization header for *.tts.speech.microsoft.com calls}
Captured request
POSThttps://dev.microsofttranslator.com/apps/endpoint?api-version=1.0

HTTP 200 OK. Response contains a JWT in field 't' and Azure Cognitive Services subscription details in field 'r', including subscription-id and azure-resource-id for an Azure TTS account. Dynamic analysis confirmed this endpoint returns valid credentials when presented with the hardcoded key.

Headers
X-UserId
0f04d16a175c411e
Content-Type
application/json; charset=utf-8
X-MT-Signature
MSTranslatorAndroidApp::Vh7k9mN2pQrZ8xYwL4jA3bC6dE1fG0hI5Kn==::Thu, 05 Jun 2025 14:22:11 GMT::a8f2c01d3e5b69701f3a4d5e6c7b8901
Accept-Language
zh-Hans
X-ClientTraceId
a8f2c01d3e5b69701f3a4d5e6c7b8901
X-ClientVersion
4.0.530a 5fe1dc6c
X-HomeGeographicRegion
zh-Hans-CN
Reproduce it yourself

Uses the HMAC-SHA256 key hardcoded in the extension to request a token from dev.microsofttranslator.com. A successful HTTP 200 response with an Azure JWT confirms the key is currently valid.

Requires
  • Node.js 18+
yt-dub-ms-translator-hmac.js · js
#!/usr/bin/env node// Reproducer: confirms that the HMAC key hardcoded in// YouTube Dubbing (oglffgiaiekgeicdgkdlnlkhliajdlja) v3.9.2// is accepted by Microsoft's endpoint and returns Azure TTS credentials.const { createHmac, randomUUID } = require('crypto');const https = require('https');const SIGNATURE_APP_ID  = 'MSTranslatorAndroidApp';const SECRET_BASE64     = 'oik6PdDdMnOXemTbwvMn9de/h9lFnfBaCWbGMMZqqoSaQaqUOqjVGm5NqsmjcBI1x+sS9ugjB55HEJWRiFXYFw==';const ENDPOINT_URL      = 'https://dev.microsofttranslator.com/apps/endpoint?api-version=1.0';const CLIENT_VERSION    = '4.0.530a 5fe1dc6c';const USER_ID           = '0f04d16a175c411e';const HOME_REGION       = 'zh-Hans-CN';function toRFC1123(date) {  return date.toUTCString();}function buildSignature(endpointUrl, date) {  const encodedPath   = encodeURIComponent(endpointUrl.split('://')[1] ?? '');  const requestId     = randomUUID().replace(/-/g, '');  const formattedDate = toRFC1123(date);  const plaintext     = (SIGNATURE_APP_ID + encodedPath + formattedDate + requestId).toLowerCase();  const keyBytes      = Buffer.from(SECRET_BASE64, 'base64');  const hmac          = createHmac('sha256', keyBytes);  hmac.update(plaintext);  const sigB64 = hmac.digest('base64');  return {    signature: `${SIGNATURE_APP_ID}::${sigB64}::${formattedDate}::${requestId}`,    requestId  };}function httpsRequest(options) {  return new Promise((resolve, reject) => {    const req = https.request(options, res => {      let data = '';      res.on('data', chunk => data += chunk);      res.on('end', () => resolve({ status: res.statusCode, body: data }));    });    req.on('error', reject);    req.end();  });}async function main() {  const now = new Date();  const url = new URL(ENDPOINT_URL);  const { signature, requestId } = buildSignature(ENDPOINT_URL, now);  console.log('Sending token request to', ENDPOINT_URL);  const res = await httpsRequest({    method:   'POST',    hostname: url.hostname,    path:     url.pathname + url.search,    headers: {      'Accept-Language':          'zh-Hans',      'X-ClientVersion':          CLIENT_VERSION,      'X-UserId':                 USER_ID,      'X-HomeGeographicRegion':   HOME_REGION,      'X-ClientTraceId':          requestId,      'X-MT-Signature':           signature,      'Content-Type':             'application/json; charset=utf-8',      'Content-Length':           '0'    }  });  console.log('HTTP status:', res.status);  console.log('Response body:', res.body);  if (res.status === 200) {    console.log('\n[CONFIRMED] Key accepted — Azure TTS credentials returned.');  } else {    console.log('\n[NOT CONFIRMED] Unexpected status — key may have been rotated.');  }}main().catch(err => { console.error(err); process.exit(1); });
How to run it
  1. 1node yt-dub-ms-translator-hmac.js
External services accessed using the hardcoded key
    • dev.microsofttranslator.com

    Microsoft's translator endpoint service. Validates the HMAC-SHA256 signature and returns a short-lived Azure Cognitive Services JWT. Operated by Microsoft Corporation.

    • eastasia.tts.speech.microsoft.com

    Azure Cognitive Services text-to-speech API. The JWT above is used as the Authorization header. Other Azure regions may also apply depending on the response.

    • yd.transduck.com

    Server-time synchronization endpoint queried before signature generation to account for clock skew. Operated by the extension developer.

Updated 30 September 2026oglffgiaiekgeicdgkdlnlkhliajdlja