twDisplayVicinity

ID: anmfeeanmnmdkjlhojpodibignbcfgjm

Could be malicious

Supported Languages

🇺🇸English
🇯🇵Japanese

Extension Info & Metadata

Status
Removed
Version
0.3.3.0
Size
0.20 MB
Rating
4.5/5
Reviews
42
Users
11,523
Type
Extension
Updated
Sep 29, 2022
Category
22_accessibility
Price
Free
Featured
No
Visibility
Listed
Mature
No
By Google
No
Trusted
Yes

Publisher Contextual Analysis

Trusted
Author
https://memo.furyutei.workView Profile
MX records exist
Yes
Domain exists
Yes
Is disposable
No
Is role-based
No
Mailbox exists
Yes
Website
Visit
Total Extensions
3
Active
0
Obsolete
3
Listed
3
Unlisted
0
Total Users
286,858

Display the vicinity of a particular tweet on Twitter.

On Twitter's official website (https://twitter.com/*), display tweets before and after a specific tweet in timeline format. It is useful when you want to know what the same person is tweeting about before and after a tweet. ========== - Retweeted - Introduced in blogs etc. - Hit with search engine You might not know what tweets were around before and after. If you can read the tweets before and after, you may be able to see an unexpected context you did not understand from a single tweet. When installing this extension, the "vicinify(neighbor)" link will be displayed when you see Twitter's timeline or single tweet. By clicking on this link, a separate tab / another window opens, you can see the timeline before and after that tweet. Also, if your tweets are retweeted, opening the "Notification" timeline (https://twitter.com/i/notifications) will also display the "vicinity" link in the notice of the retweet. By clicking, you can see what the person is tweeting about RT tweets.

Item
Type
Severity
Description
declarativeNetRequest
Permission
Critical
This permission allows the extension to define rules to block, redirect, or modify network requests. Rated Critical because it can control all network traffic, potentially blocking security updates or redirecting to malicious sites.
Contextual Risk Factors
Risk Factor
High
The following context increases the overall risk:• 20% increase: Access to sensitive domains increases potential impact• 10% increase: Early script execution enables pre-emptive content manipulation
storage
Permission
Medium
This permission allows storing data locally in the browser. Rated Medium because it can persist sensitive user data, track user activities over time, and potentially store malicious payloads.
declarativeNetRequestFeedback
Permission
Medium
This permission provides network request modification logs. Rated Medium because it can monitor network request changes and debug traffic modifications.
*://*.twitter.com/*
Host
Medium
Host permission — access limited to this URL pattern.
Access to Sensitive Domains
Risk Factor
Medium
This extension requests access to sensitive domains: *://*.twitter.com/*
Early Content Script Execution
Risk Factor
Medium
This extension runs content scripts at document_start.

Uses declarativeNetRequest to forcibly downgrade Cross-Origin-Opener-Policy and Cross-Origin-Embedder-Policy on twitter.com responses to 'unsafe-none'. Weakening these browser-level isolation headers reduces cross-origin protections, allowing the extension's injected page-context scripts (and any popup it opens via window.open) to retain references to and manipulate the parent window across navigations.

scripts/background.js (Line 270)
const  net_request_rules = [{      "id": 10,      "priority": 1,      "action": {        "type": "modifyHeaders",        "responseHeaders": [{            "header": "cross-origin-embedder-policy",            "operation": "set",            "value": "unsafe-none"          },          {            "header": "cross-origin-opener-policy",            "operation": "set",            "value": "unsafe-none"          }        ]      },      "condition": {        "urlFilter": "||twitter.com",        "resourceTypes": [          "main_frame",          "sub_frame",          "xmlhttprequest"        ]      }    },

Monkey-patches XMLHttpRequest.prototype.open to silently rewrite both the destination URL (via url_filter) and the responseText / responseURL the calling page sees (via response_filter). Object.defineProperty is used to make the read-only response properties writable so the page reads attacker-controlled content. This is a classic in-page network-interception / response-tampering primitive.

scripts/intercept_xhr.js (Line 13)
window.XMLHttpRequest.prototype.open = function(method, url, async, user, password) {  var xhr = this,    called_url = url,    replaced_url = url,    config = configs.slice()    .reverse()    .filter(config => config.reg_url.test(url || ''))[0],    url_filter = config.url_filter,    response_filter = config.response_filter;  if (typeof url_filter == 'function') {    arguments[1] = replaced_url = url_filter(url || '');    if (typeof response_filter != 'function') {      response_filter = (original_responseText, replaced_url, called_url, original_responseURL) =>        original_responseText;    }  }  xhr._called_url = called_url;  xhr._replaced_url = replaced_url;  if (async !== false) {    if (typeof response_filter == 'function') {      xhr.addEventListener('readystatechange', function(event) {        if (xhr.readyState != 4) {          return;        }        var original_responseURL = event.target.responseURL,          original_responseText = event.target.responseText,          filterd_responseText = response_filter(original_responseText, replaced_url, called_url,            original_responseURL);        Object.defineProperty(xhr, 'responseURL', {          writable: true        });        xhr.responseURL = called_url;        xhr._original_responseURL = original_responseURL;        Object.defineProperty(xhr, 'responseText', {          writable: true        });        xhr.responseText = filterd_responseText;        xhr._original_responseText = original_responseText;      });    }  }  return original_prototype_open.apply(xhr, arguments);};

Hardcodes Twitter web-client bearer tokens and harvests the user's ct0 CSRF cookie directly from document.cookie to forge authenticated OAuth2Session calls against api.twitter.com with credentials:'include'. This impersonates the logged-in user from page context and is the standard pattern used to silently scrape a user's timeline using their session.

scripts/fetch_wrapper.js (Line 149)
api1_bearer =  'AAAAAAAAAAAAAAAAAAAAAF7aAAAAAAAASCiRjWvh7R5wxaKkFp7MM%2BhYBqM%3DbQ0JPmjU9F6ZoMhDfI4uTNAaQuTDm2uO9x3WFVr2xBZ2nhjdP0',  api2_bearer =  'AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs%3D1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA',  ...  headers: {    'authorization': 'Bearer ' + ((api_user_timeline_url.indexOf('/2/') < 0) ? api1_bearer :      api2_bearer),    'x-csrf-token': document.cookie.match(/ct0=(.*?)(?:;|$)/)[1],    'x-twitter-active-user': 'yes',    'x-twitter-auth-type': 'OAuth2Session',    'x-twitter-client-language': 'en',  },  mode: 'cors',  credentials: 'include',

Provides generic helpers (inject_script_sync, inject_code, inject_code_sync) that lift a nonce off the host page's existing <script nonce> tag and use it to inject extension-controlled <script> elements (or arbitrary inline JS strings) into the page's main world, bypassing twitter.com's CSP. This nonce-stealing pattern lets the extension execute code in the page origin with full access to cookies, tokens, and authenticated APIs.

scripts/inject_script.js (Line 84)
inject_script_sync: (script_url, nonce) => {    if (!/^(https?:)?\/\//.test(script_url)) {      try {        script_url = chrome.runtime.getURL(script_url);      } catch (error) {        script_url = new URL(script_url, location.href)          .href;      }    }    let script = create_script(nonce);    script.async = false;    script.src = script_url;    document.documentElement.insertBefore(script, document.documentElement.firstChild);    script.remove();  },  ...  inject_code_sync: (code, nonce) => {    let script = create_script(nonce);    script.async = false;    script.textContent = code;    document.documentElement.appendChild(script);    script.remove();  },

Same credential-forging pattern repeated in the main content script: reads ct0 from document.cookie and combines it with hardcoded Twitter web bearer tokens to build OAuth2Session-authenticated API request headers. The extension then issues authenticated calls to user_timeline / search / statuses/retweets endpoints on the user's behalf, scraping data from Twitter as the logged-in user.

scripts/main_react.js (Line 979)
api_get_csrf_token = () => {    var csrf_token;    try {      csrf_token = document.cookie.match(/ct0=(.*?)(?:;|$)/)[1];    } catch (error) {}    return csrf_token;  },  create_api_header = (api_url) => {    return {      'authorization': 'Bearer ' + (((api_url || '')        .indexOf('/2/') < 0) ? API_AUTHORIZATION_BEARER : API2_AUTHORIZATION_BEARER),      'x-csrf-token': api_get_csrf_token(),      'x-twitter-active-user': 'yes',      'x-twitter-auth-type': 'OAuth2Session',      'x-twitter-client-language': LANGUAGE,    };  },

Strips the Cookie header from requests to api.twitter.com/oauth2/token (so the extension can mint anonymous app-only OAuth2 access tokens against the Twitter API without binding them to the user) and spoofs the User-Agent to an old Trident/Waterfox value on requests bearing a custom __twdv=legacy marker. Both rules are network-interception primitives used to evade Twitter's normal authentication/UA-based serving paths.

scripts/background.js (Line 299)
{  "id": 20,  "priority": 2,  "action": {    "type": "modifyHeaders",    "requestHeaders": [{      "header": "cookie",      "operation": "remove"    }]  },  "condition": {    "urlFilter": "||api.twitter.com/oauth2/token",    "resourceTypes": [      "main_frame",      "sub_frame",      "xmlhttprequest"    ]  }}, {  "id": 30,  "priority": 2,  "action": {    "type": "modifyHeaders",    "requestHeaders": [{      "header": "user-agent",      "operation": "set",      "value": "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; AS; rv:11.0) Waterfox/56.2"    }]  },

The service worker exposes a generic FETCH_JSON message handler that performs an arbitrary fetch() on any URL/options provided by content scripts and returns the parsed JSON. Although callers in this extension only pass twitter.com URLs, the handler itself does no URL allowlisting, giving any compromised content script (or page able to message the extension) a CORB/CORS bypass primitive via the privileged background context.

scripts/background.js (Line 164)
case 'FETCH_JSON':log_debug('FETCH_JSON', message);fetch(message.url, message.options)  .then(response => response.json())  .then((json) => {    log_debug('FETCH_JSON => json', json);    sendResponse({      json: json,    });  })  .catch((error) => {    log_error('FETCH_JSON => error', error);    sendResponse({      error: error,    });  });return true;

Captured XHR request bodies and decoded JSON responses for every twitter.com API call are forwarded via window.postMessage to the content script for further processing. While the target origin is restricted to location.origin (twitter.com), this still exfiltrates the contents of authenticated API responses (timelines, user data, retweet info) out of the page into the extension, materially expanding what the extension sees beyond what its declared permissions imply.

scripts/fetch_wrapper.js (Line 162)
write_data = (() => {      var fetch_wrapper_container = document.querySelector('#' + container_dom_id);      return (data, data_dom_id, reg_url_list) => {          var url = data.url;          if (!reg_url_list.some(reg_url_filter => reg_url_filter.test(url))) {            return;          }          window.postMessage({            namespace: params.SCRIPT_NAME,            message_id: message_id_map[data_dom_id],            url: url,            data: data,          }, location.origin);

Reaches into Twitter's React app private state (window.__INITIAL_STATE__.featureSwitch) using a MutationObserver and silently flips the user's server-delivered feature flags (responsive_web_graphql_profile_timeline) to force a different code path. Tampering with internal app feature switches behind the user's back is suspicious behavior and is also brittle/easily abused.

scripts/feature_switch.js (Line 19)
if (!window.__INITIAL_STATE__) {  return;}observer.disconnect();const featureSwitch = window.__INITIAL_STATE__.featureSwitch;...try {  if (DEBUG) console.debug('featureSwitch.defaultConfig.responsive_web_graphql_profile_timeline.value:',    featureSwitch.defaultConfig.responsive_web_graphql_profile_timeline.value, '=>', false);  featureSwitch.defaultConfig.responsive_web_graphql_profile_timeline.value = false;} catch (error) {  console.error('[twDisplayVicinity]', error);}try {  if (DEBUG) console.debug('featureSwitch.user.config.responsive_web_graphql_profile_timeline.value:',    featureSwitch.user.config.responsive_web_graphql_profile_timeline.value, '=>', false);  featureSwitch.user.config.responsive_web_graphql_profile_timeline.value = false;} catch (error) {  console.error('[twDisplayVicinity]', error);}

By severity

Critical0
High5
Medium4
Low0

Versions scanned

Showing 1 of 22 scanned versions with more than one unique finding. Counts are unique findings that include each version.

Extension VersionCode Review Findings
0.3.3.09

Files with findings

6 distinct paths — top paths by unique finding count:

  • scripts/background.js3
  • scripts/fetch_wrapper.js2
  • scripts/feature_switch.js1
  • scripts/inject_script.js1
  • scripts/intercept_xhr.js1
  • scripts/main_react.js1
S.No.
Category
Severity
File
Summary
Found in Version
1Code Injection
high
scripts/inject_script.js (line 84)Provides generic helpers (inject_script_sync, inject_code, inject_code_sync) that lift a nonce off the host page's existing <script nonce> tag and use it to inject extension-controlled <script> elements (or arbitrary …
2Credential Theft
high
scripts/fetch_wrapper.js (line 149)Hardcodes Twitter web-client bearer tokens and harvests the user's ct0 CSRF cookie directly from document.cookie to forge authenticated OAuth2Session calls against api.twitter.com with credentials:'include'. This impe…
3Credential Theft
high
scripts/main_react.js (line 979)Same credential-forging pattern repeated in the main content script: reads ct0 from document.cookie and combines it with hardcoded Twitter web bearer tokens to build OAuth2Session-authenticated API request headers. Th…
4Network Interception
high
scripts/intercept_xhr.js (line 13)Monkey-patches XMLHttpRequest.prototype.open to silently rewrite both the destination URL (via url_filter) and the responseText / responseURL the calling page sees (via response_filter). Object.defineProperty is used …
5Privilege Escalation
high
scripts/background.js (line 270)Uses declarativeNetRequest to forcibly downgrade Cross-Origin-Opener-Policy and Cross-Origin-Embedder-Policy on twitter.com responses to 'unsafe-none'. Weakening these browser-level isolation headers reduces cross-ori…
6Network Interception
medium
scripts/background.js (line 299)Strips the Cookie header from requests to api.twitter.com/oauth2/token (so the extension can mint anonymous app-only OAuth2 access tokens against the Twitter API without binding them to the user) and spoofs the User-A…
7Network Interception
medium
scripts/background.js (line 164)The service worker exposes a generic FETCH_JSON message handler that performs an arbitrary fetch() on any URL/options provided by content scripts and returns the parsed JSON. Although callers in this extension only pa…
8Other
medium
scripts/feature_switch.js (line 19)Reaches into Twitter's React app private state (window.__INITIAL_STATE__.featureSwitch) using a MutationObserver and silently flips the user's server-delivered feature flags (responsive_web_graphql_profile_timeline) t…
9Unauthorized Data Collection
medium
scripts/fetch_wrapper.js (line 162)Captured XHR request bodies and decoded JSON responses for every twitter.com API call are forwarded via window.postMessage to the content script for further processing. While the target origin is restricted to locatio…
URLs
90
IPv4
5
IPv6
0

URLs

View the external URLs this extension communicates with to understand its network activity and data interactions.

Gain full insight into all external connections.

Upgrade for full visibility.

github.com/furyutei/twMediaDownloader/issues/89https://github.com/furyutei/twMediaDownloader/issues/89#issuecomment-1261621380
groups.google.com/a/chromium.org/g/chromium-extensions/c/lLb3EJzjw0ohttps://groups.google.com/a/chromium.org/g/chromium-extensions/c/lLb3EJzjw0o
github.com/furyutei/twDisplayVicinity_Chromehttps://github.com/furyutei/twDisplayVicinity_Chrome
memo.furyutei.work/abouthttps://memo.furyutei.work/about#send_donation
www.inkscape.org-http://www.inkscape.org/
www.w3.org/2000/svghttp://www.w3.org/2000/svg
creativecommons.org/nshttp://creativecommons.org/ns#
purl.org/dc/elements/1.1/http://purl.org/dc/elements/1.1/
www.openswatchbook.org/uri/2009/osbhttp://www.openswatchbook.org/uri/2009/osb
www.w3.org/1999/02/22-rdf-syntax-nshttp://www.w3.org/1999/02/22-rdf-syntax-ns#
Showing 1 to 10 of 90 rows
Rows per page:

Gain full insight into all external connections.

Upgrade for full visibility.

0.3.3.0
IPv4
-
0.3.2.25
IPv4
-
0.2.6.15
IPv4
-
0.2.3.10
IPv4
-
0.2.6.7
IPv4
-
Showing 1 to 10 of 30 rows
Rows per page:

Code Diff

Compare extension code between any two versions.

0 changed files (scanned top 25 shared text files)

No comparable text files found between these versions.

Browse and explore files within this extension package

Gain full insight into all external connections.

Upgrade for full visibility.