ClickFix Browser Injection and Extension Persistence
An intruder has used a social engineering lure to trick a user into manually injecting a JavaScript loader or installing a malicious Tampermonkey script that facilitates persistent cryptocurrency theft via the Google Visualization API.
Based on research by Cisco Talos 2026-09-28 12 steps · 5 queries T1059.001 T1115 T1176 T1566
Brief
Why This Hunt
Adversaries behind the ClickFix campaign are moving away from operating system payloads and focusing on the browser. As detailed by Cisco Talos in ClickFix moves into the browser: Cryptocurrency theft with Google-hosted C2, attackers use social engineering to trick users into manually executing malicious code or installing extensions. This shift bypasses many endpoint detection rules that look for process hollowing or unusual child processes. Confirming the integrity of the browser session is now a prerequisite for financial security.
How the Hunt Flows
The hunt begins by scoping the environment for the Tampermonkey extension. While the extension is legitimate and used by many practitioners, it serves as the primary persistence mechanism for the malicious scripts in this campaign. Narrowing the scope to hosts with this extension reduces the data volume for subsequent steps and focuses efforts on the most likely targets.
Next, the hunt correlates delivery signals with execution in a parallel triage phase. It searches for HTTP traffic to known lure domains like Google Docs and Paste.sh, specifically looking for the specific path patterns or document IDs used in the campaign. Simultaneously, it examines script activity for patterns associated with the Google Visualization API (Gviz). The ClickFix loader uses the Gviz API for command and control by pulling data from attacker-controlled Google Spreadsheets.
An analyst then triages these early signals to find hosts where a lure visit was followed closely by a Gviz script execution. For these high-interest hosts, the hunt enters a follow-on phase to investigate persistence and collection behavior. It identifies file modifications within the Tampermonkey storage directories, which confirms that the loader successfully installed a persistent user script.
Finally, the hunt uses process prevalence to find the "tell" of a cryptocurrency skimmer. It identifies rare instances of clipboard manipulation tools like clip.exe or PowerShell's clipboard cmdlets. The adversary uses these tools to perform address swapping: when a user copies a destination wallet address, the skimmer replaces it with an attacker-controlled address. By filtering for low-prevalence commands, the hunt separates malicious activity from standard administrative scripts.
Blind Spots
This hunt has two primary limitations. First, if a user injects the script directly into the browser's memory via the navigation bar or console without triggering persistence, the activity might leave no footprint on the monitored surfaces. Second, the hunt can identify that Tampermonkey is writing to its database files, but it cannot inspect the actual script text inside extension-managed storage without specialized forensic tooling or manual profile auditing.
Steps
-
Scope hosts with Tampermonkey installed
Query · scopingIdentify hosts where the Tampermonkey extension is present, as it is the campaign's primary method for script persistence.
reads hb_software_inventorysqlSELECT device_hostname, package_name, package_version, package_uid FROM hb_software_inventory WHERE (LOWER(package_name) LIKE '%tampermonkey%' OR package_uid = 'dhdgffkkebhmkfjojejmpbldmpobfkfo') AND asset_scope = 'endpoint'What a hit looks like. A list of hosts with the extension. Silence indicates low baseline risk for the persistence stage of this specific campaign.
-
HTTP traffic to lure domains
Query · baselineIdentify users accessing the Google Docs or Paste sites mentioned in the social engineering lures.
reads hb_http_activitysqlSELECT device_hostname, url_hostname, url_path, time FROM hb_http_activity WHERE ('{{scope_hosts}}' = '' OR instr(',' || '{{scope_hosts}}' || ',', ',' || device_hostname || ',') > 0) AND instr(',' || '{{lure_domains}}' || ',', ',' || LOWER(url_hostname) || ',') > 0 AND (LOWER(url_path) LIKE '%/document/d/%' OR LOWER(url_path) LIKE '%/spreadsheets/d/%' OR instr(',' || '{{lure_path_patterns}}' || ',', ',' || LOWER(url_path) || ',') > 0) AND time >= datetime('now', '-{{lookback_days}} days')What a hit looks like. Hosts visiting the specific Google Docs or Paste.sh links. This provides the context for subsequent script execution.
-
Google Visualization API script execution
Query · detection candidateDetect the execution of the first-stage loader script which uses the Gviz API for C2.
reads hb_script_activitysqlSELECT device_hostname, actor_user_name, script_content, time FROM hb_script_activity WHERE ('{{scope_hosts}}' = '' OR instr(',' || '{{scope_hosts}}' || ',', ',' || device_hostname || ',') > 0) AND (instr(LOWER(script_content), 'gviz/tq') > 0 OR instr(LOWER(script_content), 'google.visualization') > 0) AND time >= datetime('now', '-{{lookback_days}} days')What a hit looks like. Script contents showing query construction against Google spreadsheets. This is the primary indicator of the ClickFix loader.
-
Triage early loader activity
Agent triageSynthesize the HTTP and script evidence to identify hosts that likely moved from lure access to loader execution.
-
Tampermonkey persistence files
Query · enrichmentFind file modifications in the Tampermonkey storage directory.
reads hb_file_activitysqlSELECT device_hostname, file_path, file_name, time FROM hb_file_activity WHERE ('{{scope_hosts}}' = '' OR instr(',' || '{{scope_hosts}}' || ',', ',' || device_hostname || ',') > 0) AND LOWER(file_path) LIKE '%tampermonkey%' AND time >= datetime('now', '-{{lookback_days}} days')What a hit looks like. Writes to extension storage. This confirms the 'persistence' stage of the campaign.
-
Rare clipboard manipulation
Query · baselineDetect the address-swapping behavior of the skimmer by identifying rare usage of clipboard interaction tools.
reads hb_process_activitysqlSELECT LOWER(process_cmd_line) AS cmd, COUNT(DISTINCT device_hostname) AS hosts, MIN(time) AS first_seen FROM hb_process_activity WHERE ('{{scope_hosts}}' = '' OR instr(',' || '{{scope_hosts}}' || ',', ',' || device_hostname || ',') > 0) AND (LOWER(process_name) LIKE '%clip.exe' OR LOWER(process_cmd_line) LIKE '%get-clipboard%' OR LOWER(process_cmd_line) LIKE '%set-clipboard%') AND time >= datetime('now', '-{{lookback_days}} days') GROUP BY cmd HAVING hosts <= 3What a hit looks like. Low-prevalence clipboard manipulation. Fleet-wide admin scripts will be filtered out, leaving manual or malicious activity.
-
Synthesize full attack chain
Agent triageFinal assessment to confirm hosts demonstrating the full path from delivery to collection.
-
Infection routing
DecisionRoute results based on the agent's synthesis of the full attack chain.
-
Isolate host and revoke sessions
Response actionPrevent further financial loss and C2 communication by isolating the affected endpoint.
-
Forensic extension audit
Analyst taskAnalyst manual review of extension storage and browser profiles to extract the malicious script content and identify the C2 spreadsheet.
-
Close out and document
Analyst taskFinal documentation of findings and closure of the hunt.
Coverage
Scenario coverage
| Stage | Covered | How, or why not |
|---|---|---|
| Social Engineering Lure Delivery T1566 |
Yes | lure-delivery-http |
| User-Assisted Script Injection T1059.001 |
Yes | loader-execution-scripts |
| Browser Extension Persistence T1176 |
Yes | scoping-tampermonkey, persistence-tampermonkey-files |
| Cryptocurrency Theft and Skimming T1115 |
Yes | collection-clipboard-skimmer |
| Google Visualization API C2 T1071 |
Out of scope | Belongs to another part of the 'ClickFix moves into the browser: Cryptocurrency theft with Google-hosted C2' series. |
Blind spots
- Needs Browser-internal instrumentation. A user-injected script that does not trigger persistence may execute entirely in-memory and be invisible to script surfaces. It would answer Was the script injected only into memory via the navigation bar without triggering script-block logging?.
- Needs Extension-specific database parsing. The hunt can see file writes to extension folders, but cannot read the script text inside extension-managed IndexedDB or storage files without forensic tooling. It would answer What is the content of the scripts stored inside Tampermonkey's private database?.
Parameters & data
Parameters
| Parameter | Type | Default | What it is |
|---|---|---|---|
lookback_days | number | 14 | Days of history to examine. |
lure_domains | list[domain] | paste.sh, docs.google.com | Domains used to host lures and first-stage loader scripts. |
lure_path_patterns | list[string] | /document/d/, /spreadsheets/d/ | Specific URL path patterns or fragments found in social engineering lures. |
scope_hosts | list[host] | — | Narrow the hunt to specific hosts; leave empty to scan the entire estate. |
Telemetry
| Source | Category | Telemetry |
|---|---|---|
| Endpoint telemetry (hb_ surfaces) | endpoint | endpoint |
| Web server / proxy logs | siem | network |
Source
---
analysis: A standard rule might fire on the gviz string, but a hunt is required to
follow the chain from an HTTP lure to manual injection and finally to persistence
in an extension. This hunt correlates software inventory, HTTP, script blocks, file
activity, and process prevalence to confirm an intrusion.
blind_spots:
- id: browser-memory-blind-spot
question: Was the script injected only into memory via the navigation bar without
triggering script-block logging?
requires: Browser-internal instrumentation
risk: A user-injected script that does not trigger persistence may execute entirely
in-memory and be invisible to script surfaces.
stage: user-assisted-script-injection
- id: encrypted-extension-data
question: What is the content of the scripts stored inside Tampermonkey's private
database?
requires: Extension-specific database parsing
risk: The hunt can see file writes to extension folders, but cannot read the script
text inside extension-managed IndexedDB or storage files without forensic tooling.
stage: browser-extension-persistence
coverage:
- stage: social-engineering-lure-delivery
status: covered
steps:
- lure-delivery-http
- stage: user-assisted-script-injection
status: covered
steps:
- loader-execution-scripts
- stage: browser-extension-persistence
status: covered
steps:
- scoping-tampermonkey
- persistence-tampermonkey-files
- stage: cryptocurrency-theft-and-skimming
status: covered
steps:
- collection-clipboard-skimmer
- reason: 'Belongs to another part of the ''ClickFix moves into the browser: Cryptocurrency
theft with Google-hosted C2'' series.'
stage: google-visualization-api-c2
status: out_of_scope
guardrails:
claims: no_unsupported
evidence: citation_required
missing_data: not_benign
telemetry: untrusted
hunt:
applicability: campaign-specific
handoff: promote-to-detection
justification: Browser-based script injection and persistence bypass traditional
OS security controls and directly threaten financial assets; confirming the integrity
of the user's web interaction surface is essential.
methodology: model-assisted
trigger: intel-report
hypothesis: An intruder has used a social engineering lure to trick a user into manually
injecting a JavaScript loader or installing a malicious Tampermonkey script that
facilitates persistent cryptocurrency theft via the Google Visualization API.
labels:
- hunt
- attack.t1566
- attack.t1059.001
- attack.t1176
- attack.t1115
name: ClickFix Browser Injection and Extension Persistence
parameters:
lookback_days:
default: '14'
description: Days of history to examine.
type: number
lure_domains:
default:
- paste.sh
- docs.google.com
description: Domains used to host lures and first-stage loader scripts.
from:
kind: article
observed: '2026-09-08'
ref: talos-clickfix-2026
type: list[domain]
lure_path_patterns:
default:
- /document/d/
- /spreadsheets/d/
description: Specific URL path patterns or fragments found in social engineering
lures.
from:
kind: article
observed: '2026-09-08'
ref: talos-clickfix-2026
type: list[string]
scope_hosts:
default: []
description: Narrow the hunt to specific hosts; leave empty to scan the entire
estate.
type: list[host]
provenance:
authors:
- name: Huntbase hunt generation
org: huntbase.io
generated:
by: huntbase-hunt-generation
from: https://blog.talosintelligence.com/clickfix-moves-into-the-browser/
gates:
- dry-run
- lint
model: hb_google/gemini-3-flash-preview
rationale: Focus on endpoints with Tampermonkey installed first. Prioritize users
with known access to financial or cryptocurrency domains.
references:
- name: "Cisco Talos \u2014 ClickFix moves into the browser: Cryptocurrency theft\
\ with Google-hosted C2"
url: https://blog.talosintelligence.com/clickfix-moves-into-the-browser/
related:
- hunt: google-visualization-api-c2
reason: The C2 hunt focuses on broader network patterns of Gviz abuse, while this
hunt focuses on the user-assisted injection and extension persistence scenario.
relation: out-of-scope-alternative
scenario:
stages:
- name: Social Engineering Lure Delivery
observables:
- Telegram channel posts
- DarkForums posts
- paste.sh links
- 'Google Docs filename: ''API Logic Flaw'''
- 'Google Docs URL: docs.google.com/document/d/'
slug: social-engineering-lure-delivery
tactic: initial-access
techniques:
- T1566
- name: User-Assisted Script Injection
observables:
- 'javascript: protocol used in Chrome navigation bar'
- Pasting obfuscated JS from paste.sh
- Base64 encoded strings in browser memory
- Injection into DOM <script> elements
slug: user-assisted-script-injection
tactic: execution
techniques:
- T1059.001
- name: Browser Extension Persistence
observables:
- Tampermonkey extension installation
- Malicious loader script in Tampermonkey configuration
- Scripts targeting simpleswap.io or swapzone.io
slug: browser-extension-persistence
tactic: persistence
techniques:
- T1176
- name: Google Visualization API C2
observables:
- docs.google.com/spreadsheets/d/*/gviz/tq
- 'Visualization API queries: SELECT B, SELECT A'
- JSON formatted data returned from Google Sheets
- Appended data via HTML POST to Google Forms
slug: google-visualization-api-c2
tactic: command-and-control
techniques:
- T1071
- name: Cryptocurrency Theft and Skimming
observables:
- Hooking browser fetch API
- Replacing cryptocurrency deposit addresses in server responses
- Replacing user clipboard content
- Displaying counterfeit 'bonus' UI elements
slug: cryptocurrency-theft-and-skimming
tactic: collection
techniques:
- T1115
summary: Actors lure cryptocurrency traders via Telegram and dark web forums to
'exploit' non-existent API flaws using a variation of ClickFix social engineering.
Victims are tricked into manually injecting malicious JavaScript into their browsers
or the Tampermonkey extension, which establishes persistence and uses the Google
Visualization API to fetch second-stage skimmers from public Google Sheets to
steal cryptocurrency by hijacking the clipboard.
series:
index: 1
slug: clickfix-moves-into-the-browser-cryptocurrency-theft-with-google-hosted-c2
title: 'ClickFix moves into the browser: Cryptocurrency theft with Google-hosted
C2'
total: 2
severity: medium
targets:
analyst:
name: Tier-2 analyst
role: analyst
endpoint:
category: endpoint
name: Endpoint telemetry (hb_ surfaces)
telemetry:
- endpoint
hunter:
agent: true
name: Hunt agent
web:
category: siem
name: Web server / proxy logs
telemetry:
- network
tlp: clear
type: investigation
---
# ClickFix Browser Injection and Extension Persistence
This hunt identifies ClickFix campaigns targeting browser sessions rather than the operating system. It identifies the delivery of social engineering lures via Google Docs and the subsequent persistence through the Tampermonkey extension. The hunt follows a phased flow: first scoping for the extension, then identifying initial delivery and execution signals, and finally corroborating with file-based persistence and behavioral indicators of cryptocurrency skimming like rare clipboard manipulation.
## scoping-tampermonkey
<!-- Scope hosts with Tampermonkey installed -->
Identify hosts where the Tampermonkey extension is present, as it is the campaign's primary method for script persistence.
```sqlite target=endpoint role=scoping
~~~yaml
expected: A list of hosts with the extension. Silence indicates low baseline risk
for the persistence stage of this specific campaign.
reads:
- asset_scope
- device_hostname
- package_name
- package_uid
- package_version
silence: not_evidence_of_absence
source: hb_software_inventory
verified: dry-run
verified_at: '2026-09-28'
~~~
SELECT device_hostname, package_name, package_version, package_uid FROM hb_software_inventory WHERE (LOWER(package_name) LIKE '%tampermonkey%' OR package_uid = 'dhdgffkkebhmkfjojejmpbldmpobfkfo') AND asset_scope = 'endpoint'
```
## parallel-early-signals
<!-- Initial lure and loader signals -->
parallel:
- → lure-delivery-http
- → loader-execution-scripts
join: → agent-early-triage
## lure-delivery-http
<!-- HTTP traffic to lure domains -->
Identify users accessing the Google Docs or Paste sites mentioned in the social engineering lures.
```sqlite target=web role=baseline params=(lookback_days=lookback_days, lure_domains=lure_domains, lure_path_patterns=lure_path_patterns, scope_hosts=scope_hosts)
~~~yaml
expected: Hosts visiting the specific Google Docs or Paste.sh links. This provides
the context for subsequent script execution.
reads:
- device_hostname
- time
- url_hostname
- url_path
silence: not_evidence_of_absence
source: hb_http_activity
verified: dry-run
verified_at: '2026-09-28'
~~~
SELECT device_hostname, url_hostname, url_path, time FROM hb_http_activity WHERE ('{{scope_hosts}}' = '' OR instr(',' || '{{scope_hosts}}' || ',', ',' || device_hostname || ',') > 0) AND instr(',' || '{{lure_domains}}' || ',', ',' || LOWER(url_hostname) || ',') > 0 AND (LOWER(url_path) LIKE '%/document/d/%' OR LOWER(url_path) LIKE '%/spreadsheets/d/%' OR instr(',' || '{{lure_path_patterns}}' || ',', ',' || LOWER(url_path) || ',') > 0) AND time >= datetime('now', '-{{lookback_days}} days')
```
## loader-execution-scripts
<!-- Google Visualization API script execution -->
Detect the execution of the first-stage loader script which uses the Gviz API for C2.
```sqlite target=endpoint role=detection-candidate params=(lookback_days=lookback_days, scope_hosts=scope_hosts)
~~~yaml
expected: Script contents showing query construction against Google spreadsheets.
This is the primary indicator of the ClickFix loader.
reads:
- actor_user_name
- device_hostname
- script_content
- time
silence: not_evidence_of_absence
source: hb_script_activity
verified: dry-run
verified_at: '2026-09-28'
~~~
SELECT device_hostname, actor_user_name, script_content, time FROM hb_script_activity WHERE ('{{scope_hosts}}' = '' OR instr(',' || '{{scope_hosts}}' || ',', ',' || device_hostname || ',') > 0) AND (instr(LOWER(script_content), 'gviz/tq') > 0 OR instr(LOWER(script_content), 'google.visualization') > 0) AND time >= datetime('now', '-{{lookback_days}} days')
```
## agent-early-triage
<!-- Triage early loader activity -->
```agent target=hunter
cite: required
context:
- lure-delivery-http
- loader-execution-scripts
max_iterations: 3
objective: Determine if any host has both accessed a lure domain and executed a script
containing Gviz API patterns.
success_criteria: A per-host verdict of suspicious or malicious citing the specific
URL and script content.
tools:
- endpoint
- web
```
## parallel-follow-on
<!-- Persistence and skimming behavior -->
parallel:
- → persistence-tampermonkey-files
- → collection-clipboard-skimmer
join: → agent-final-synthesis
## persistence-tampermonkey-files
<!-- Tampermonkey persistence files -->
Find file modifications in the Tampermonkey storage directory.
```sqlite target=endpoint role=enrichment params=(lookback_days=lookback_days, scope_hosts=scope_hosts)
~~~yaml
expected: Writes to extension storage. This confirms the 'persistence' stage of the
campaign.
reads:
- device_hostname
- file_name
- file_path
- time
silence: not_evidence_of_absence
source: hb_file_activity
verified: dry-run
verified_at: '2026-09-28'
~~~
SELECT device_hostname, file_path, file_name, time FROM hb_file_activity WHERE ('{{scope_hosts}}' = '' OR instr(',' || '{{scope_hosts}}' || ',', ',' || device_hostname || ',') > 0) AND LOWER(file_path) LIKE '%tampermonkey%' AND time >= datetime('now', '-{{lookback_days}} days')
```
## collection-clipboard-skimmer
<!-- Rare clipboard manipulation -->
Detect the address-swapping behavior of the skimmer by identifying rare usage of clipboard interaction tools.
```sqlite target=endpoint role=baseline params=(lookback_days=lookback_days, scope_hosts=scope_hosts)
~~~yaml
baseline:
compare: first_seen
window: '{{lookback_days}}d'
expected: Low-prevalence clipboard manipulation. Fleet-wide admin scripts will be
filtered out, leaving manual or malicious activity.
prevalence:
by: device_hostname
key:
- cmd
rare_below: 3
reads:
- device_hostname
- process_cmd_line
- process_name
- time
silence: not_evidence_of_absence
source: hb_process_activity
verified: dry-run
verified_at: '2026-09-28'
~~~
SELECT LOWER(process_cmd_line) AS cmd, COUNT(DISTINCT device_hostname) AS hosts, MIN(time) AS first_seen FROM hb_process_activity WHERE ('{{scope_hosts}}' = '' OR instr(',' || '{{scope_hosts}}' || ',', ',' || device_hostname || ',') > 0) AND (LOWER(process_name) LIKE '%clip.exe' OR LOWER(process_cmd_line) LIKE '%get-clipboard%' OR LOWER(process_cmd_line) LIKE '%set-clipboard%') AND time >= datetime('now', '-{{lookback_days}} days') GROUP BY cmd HAVING hosts <= 3
```
## agent-final-synthesis
<!-- Synthesize full attack chain -->
```agent target=hunter
cite: required
context:
- agent-early-triage
- persistence-tampermonkey-files
- collection-clipboard-skimmer
max_iterations: 5
objective: Confirm the presence of a persistent browser-based skimmer by correlating
the early triage results with follow-on persistence and collection signals.
success_criteria: A final malicious verdict citing the specific gviz loader and the
associated persistence or skimming activity.
tools:
- endpoint
- web
```
## infection-decision
<!-- Infection routing -->
if~: "the agent-final-synthesis verdict is malicious for at least one host, citing gviz loader execution and either file persistence or skimmer activity" (confidence: high, judge=hunter)
then: → action-contain-host
indeterminate: → task-forensic-audit
unavailable: → task-forensic-audit (blind_spot: browser-memory-blind-spot)
else: → task-close-out
## action-contain-host
<!-- Isolate host and revoke sessions -->
```action target=endpoint
~~~yaml
approval: required
~~~
Isolate the host from the network. Inform the user of browser compromise and revoke active web sessions, specifically targeting crypto trading sites SimpleSwap and SwapZone.
```
→ task-forensic-audit
## task-forensic-audit
<!-- Forensic extension audit -->
```manual target=analyst
Audit the user's Chrome Profile. Inspect Tampermonkey's private storage (Local Extension Settings) for scripts targeting SimpleSwap or SwapZone. Extract any spreadsheet IDs from gviz URLs.
```
→ task-close-out
## task-close-out
<!-- Close out and document -->
```manual target=analyst
Document the hosts examined. If malicious Tampermonkey scripts were found, contribute their signatures to detection engineering for a standing rule.
```
→ end
Run it
Take this hunt into your environment.
Open it in Huntbase to run every step against your own connections, with Scout weighing the evidence and your analysts in command. Or take the open hunt.md file anywhere that reads the format.
Machine-drafted by huntbase-hunt-generation using hb_google/gemini-3-flash-preview, gated by dry-run, lint, then reviewed by a person.