Is Video Downloader Social safe?
Video Downloader is medium risk. The shipped service worker captures the outgoing header array from X.com API requests and stores it as twitter_token locally. A later function rebuilds those headers and sends a GET to X.com's timeline API using the saved auth headers.
AI-generated. Findings may contain errors. Those marked Verified have been manually reviewed.
Publishers can request a review.
Findings
X.com authentication headers are saved and reused
The shipped service worker captures the outgoing header array from X.com API requests and stores it as twitter_token locally.
A later function rebuilds those headers and sends a GET to X.com's timeline API using the saved auth headers.
What actually happens
You browse X.com while signed in.
The listener is scoped to X.com API URLs under /i/api/.
The extension saves the outgoing request headers and later uses them in its own X.com API request.
Those headers can include authorization, CSRF, cookie, and other session-related fields sent by the browser.
Header fields stored under twitter_token
- Authorization headerAuthorization: Bearer <redacted> (illustrative)
This value can make an API request act like it came from your signed-in X.com session.
- CSRF tokenx-csrf-token: 8f7b3c2e91a046d4b5c6a7e8f9012345 (illustrative)
This token is part of the browser session context that X.com expects on authenticated requests.
- X.com cookiesauth_token=<redacted>; ct0=<redacted> (illustrative)
Cookies can identify the signed-in browser session used for the API request.
- Other request headersx-twitter-active-user: yes (illustrative)
The stored array preserves the rest of the browser request context that was sent with the X.com API call.
What's stored on your device
The extension keeps a reusable copy of session headers in its own storage, not just letting the browser send them with the original request.
- Location
- chrome.storage.local key 'twitter_token'
{ "twitter_token": [ { "name": "Authorization", "value": "Bearer <redacted>" }, { "name": "x-csrf-token", "value": "8f7b3c2e91a046d4b5c6a7e8f9012345" }, { "name": "Cookie", "value": "auth_token=<redacted>; ct0=<redacted>" } ]}Captured request
- Cookie
- auth_token=<redacted>; ct0=<redacted>
- x-csrf-token
- <redacted>
- Authorization
- Bearer <redacted>
The code that does this
The worker stores X.com API headers and reuses them in a later fetch
Readable header capture
deobfuscated/js/worker.jschrome.webRequest.onBeforeSendHeaders.addListener((e => { e.requestHeaders && chrome.storage.local.set({ twitter_token: e.requestHeaders })}), { urls: ["*://*.x.com/i/api/*"]}, ["requestHeaders"])Readable header replay
deobfuscated/js/worker.jsasync fetchDataFromTwitId(t, a, s) { const o = `https://api.x.com/2/timeline/conversation/${t}.json?include_profile_interstitial_type=1&include_blocking=1&include_blocked_by=1&include_followed_by=1&include_want_retweets=1&include_mute_edge=1&include_can_dm=1&include_can_media_tag=1&skip_status=1&cards_platform=Web-12&include_cards=1&include_composer_source=true&include_ext_alt_text=true&include_reply_count=1&tweet_mode=extended&include_entities=true&include_user_entities=true&include_ext_media_color=true&include_ext_media_availability=true&send_error_codes=true&simple_quoted_tweets=true&count=20&ext=mediaStats%252ChighlightedLabel%252CcameraMoment`, n = (await chrome.storage.local.get("twitter_token")).twitter_token.reduce(((e, { name: t, value: a }) => ({ ...e, [t]: a }))); fetch(o, { method: "GET", headers: n }).then((e => e.json())).then((s => { if (s.errors) return; const o = s.globalObjects.tweets[t].extended_entities.media[0].video_info.variants, n = { fileName: `Video by ${s.globalObjects.users[s.globalObjects.tweets[t].user_id_str].name} (${t})`, url: o.filter((e => "video/mp4" === e.content_type))[0], ext: ".mp4" }; e.addVideoLinks([n], a.tab.id, a.tab.url) }))}Destination used by the replay function
- api.x.com
Receives the extension's conversation timeline GET request with the headers reconstructed from twitter_token.
