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.
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.
| Field | Value | Why it matters | |
|---|---|---|---|
Authorization header | Authorization: Bearer <redacted> (illustrative) | This value can make an API request act like it came from your signed-in X.com session. | |
CSRF token | x-csrf-token: 8f7b3c2e91a046d4b5c6a7e8f9012345 (illustrative) | This token is part of the browser session context that X.com expects on authenticated requests. | |
X.com cookies | auth_token=<redacted>; ct0=<redacted> (illustrative) | Cookies can identify the signed-in browser session used for the API request. | |
Other request headers | x-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. |
The extension keeps a reusable copy of session headers in its own storage, not just letting the browser send them with the original request.
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>"
}
]
}| Cookie | auth_token=<redacted>; ct0=<redacted> |
| x-csrf-token | <redacted> |
| Authorization | Bearer <redacted> |
The worker stores X.com API headers and reuses them in a later fetch
chrome.webRequest.onBeforeSendHeaders.addListener((e => {
e.requestHeaders && chrome.storage.local.set({
twitter_token: e.requestHeaders
})
}), {
urls: ["*://*.x.com/i/api/*"]
}, ["requestHeaders"])async 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)
}))
}- api.x.com
Receives the extension's conversation timeline GET request with the headers reconstructed from twitter_token.