Skip to content
Adform Supply Chain Attack: JavaScript Crypto Clipper Analysis

Adform Supply Chain Attack: JavaScript Crypto Clipper Analysis

Technical analysis of the Adform JavaScript supply-chain attack: four payload variants, exact-hash exposure across 59 hosts, cache replay, wallets and hunting rules.

Adform Supply Chain Attack: JavaScript Crypto Clipper Analysis

Analytical brief

Key findings

  • Malicious code was appended to the otherwise legitimate trackpoint-async.js file archives reveal several payload versions changed within hours.
  • The advanced variant replaced BTC and ETH addresses in DOM text, form fields, programmatic value setters and copy, cut, paste and input events.
  • URLScan returned 83 exact-hash observations across 59 hosts: 55 hosts had at least one variant with valid BTC and ETH replacement addresses, while four hosts only received the early variant containing invalid address strings.
  • An exact-hash response was still observed on 30 July through a custom edge domain with a Cloudflare cache HIT and an age of 245023 seconds, so cache hunting must continue beyond the central incident window.
  • Valid BTC and ETH replacement addresses were recovered from the archived variants, but blockchain inflows alone do not prove that funds were stolen through this incident.
Scope
Static analysis of the 26–27 July 2026 Adform Site Tracking JavaScript compromise, passive exposure hunting, blockchain analysis of the associated wallets and defensive hunting guidance.
Limitations
This analysis relies on public samples, web archives, URLScan and public blockchains. It does not establish every affected page or visitor, confirmed stolen funds, or attribution to a named threat actor.

In short: the advertising script decided to change careers

In late July 2026, Adform’s distributed trackpoint-async.js acquired a feature nobody had ordered. Someone attached a browser-side crypto clipper to otherwise normal tracking code. There was no need to compromise every website separately. Changing one shared third-party file was enough. From there, a visitor only had to view, enter, copy or paste a cryptocurrency address on an affected page.

And no, this was not the movie-version malware that installs itself in System32, turns the lights off and leaves a skull on the screen. According to Adform’s incident update, the code did not persist on the device and only operated while an affected page remained open. That is still more than enough time for one irreversible blockchain transaction.

What I actually examined:

  • statically separated the appended code from the legitimate library and reconstructed its versions
  • decoded the XOR-protected content without executing it
  • validated the BTC, ETH and TRON replacement values
  • searched URLScan for four exact response hashes
  • reconstructed the archived payload changes
  • examined the C2 infrastructure and public blockchain activity
  • prepared detection and threat-hunting material.

To avoid writing “that Adform clipper” throughout the article, I refer to this analytical cluster as HCVX-ADFORM-CLIPPER-2026. It is a temporary HECAVEX label, not a newly branded threat actor with an animal logo and merchandise.

Bottom line: confidence is high on the supply-chain compromise, payload behaviour and the two valid replacement addresses. The available evidence is insufficient to identify the operator, their origin or the initial access path into Adform’s distribution. We do not have a defensible total for stolen funds either.

Methodology and safety boundaries

Before getting into the code, a short OPSEC note. I saved the public sample from Max Maass’s Gist as text in a separate analysis directory. I did not load it in a browser or execute it with Node, eval, a headless browser or any other JavaScript runtime. Decoding was performed at byte level by comparing files, extracting values with regular expressions and applying XOR with the key embedded in the sample.

That is not just a decorative compliance sentence. The code was designed to hook the clipboard, DOM and form fields. Running it in a working environment “just for a quick look” would be a fairly efficient way to create your own incident.

I used the following sources so the numbers and attribution did not appear from thin air:

SourceWhat I checkedInteraction
Adform statement and documentationincident window, impact and script deployment modelpublic reading
Gist and Wayback filesstatic diff, hashes, XOR and behaviourpassive download, not executed
URLScanexact response hashes, response metadata and screenshotspassive search
RIPE RDAP / RIPEstatIP prefix, ASN and registration contextpassive lookup
Mempool and Blockscoutpublic BTC and ETH blockchain activitypassive blockchain lookup

I did not visit suspicious live hosts, scan the C2 port or send any transactions. Threat hunting, in other words, not “look, I got a shell on someone else’s system”.

Incident timeline

In its 5 August 2026 update, Adform states that the first malicious activity began at 23:49 CEST on 26 July (21:49 UTC), suspicious activity was detected at 03:00 CEST on 27 July (01:00 UTC), and no new malicious-code distribution was observed after 19:16 CEST (17:16 UTC).

The official timeline is one part of the picture. Wayback and URLScan also show how the payload changed and how a cached copy survived beyond the official incident window:

Timeline of the Adform incident and malicious JavaScript variants Times are UTC. The blue accent on the final point represents a cached response, not proven continued attacker access.

Time UTCObservationAssessment
2026-07-26 21:49First activity according to Adform’s retrospective analysisofficial start boundary
2026-07-26 23:29Wayback file contains the first block with C2 and invalid wallet valuesearly or broken stage
2026-07-27 00:00More advanced single-block variant appearsDOM, forms and programmatic value hook
2026-07-27 00:41Archive contains both blockscopy, cut, paste, input and polling
2026-07-27 01:00Adform detects suspicious activitycontainment begins
2026-07-27 17:16Adform no longer observes new malicious distributionend of the central incident window
2026-07-30 09:09URLScan receives a known exact-hash variant through s1.matas.seCloudflare HIT, stale cached object
2026-08-08Current s2.adform.net file matches the clean sample prefixresearch snapshot, not a permanent allowlist

Where the payload was attached

The diff is fairly straightforward. The beginning of the publicly captured file was byte-for-byte identical to the clean trackpoint-async.js downloaded on 8 August 2026. The difference began only after 82,727 bytes. A 6,945-byte malicious suffix had simply been appended to the legitimate library.

1
2
3
4
5
captured trackpoint-async.js
├── 82,727 B  legitimate Adform prefix
└──  6,945 B  appended malicious suffix
    ├── block A: clipboard poll + copy hook + HTTP telemetry
    └── block B: DOM walker + form/value hooks + clipboard events

An administrator sees a familiar hostname, a familiar file path and the expected vendor script. The small bonus waiting at the end was probably not requested by Marketing. One modification produced a rather effective supply-chain fan-out.

Adform’s deployment documentation says the tracking code can be used on one page, across several sections or throughout a website. Compromising the shared distribution file could therefore reach otherwise unrelated downstream pages. This is consistent with MITRE ATT&CK T1195.002: Compromise Software Supply Chain.

Four file variants, not one “malware hash”

The file changed several times during the incident, so one SHA-256 is not enough. It is a useful reminder for anyone who drops one hash into an IOC feed and ceremonially closes the incident.

SHA-256First passive timestampContent
c03567ca…31a07-26 23:29 UTCfirst block, HTTP C2, invalid replacement values
0674a58b…aa307-27 00:00 UTCadvanced single block, valid BTC/ETH
a04461bb…eb607-27 00:41 UTCboth blocks, additional paste and input hooks
02ff86c7…c5507-27 11:40 UTCfull-response advanced-only variant also observed in cache on 07-30

Full hashes and other machine-readable indicators are available in the IOC CSV.

The relationship to 02ff86c7… required a little more work, so I checked it at byte level. Taking the first 82,721 bytes and the final 4,777 bytes from the two-block a04461bb… response produces an 87,498-byte file. Its SHA-256 is exactly 02ff86c7…. This isolates the second, more advanced replacement block. The reproduction steps and assertions are available separately. There was still no reason to execute the JavaScript.

One more hash detail. The public Gist contains a comment line added by the researcher, so the complete downloaded artifact has SHA-256 e6943f22…729, while the JavaScript body itself is a04461bb…eb6. Both hashes are correct they were calculated from different content. Better to document that now than spend half an hour later wondering why “the hash does not match”.

Deobfuscation: XOR that hides more from the eye than from an analyst

Replacement values were stored as numeric arrays and XORed with a six-byte key:

1
4d 33 77 54 77 30  →  "M3wTw0"

Decoding did not require anything exotic. The following logic is enough, without eval, DOM access or sample execution:

1
2
3
4
5
def xor_decode(values: list[int], key: bytes) -> str:
    return bytes(
        value ^ key[index % len(key)]
        for index, value in enumerate(values)
    ).decode("utf-8", errors="strict")

The obfuscation level is roughly equivalent to closing the curtains and hoping the house disappears. It may still defeat automated plain-text IOC scanning, which is why defenders should hunt for the structure as well as the final wallet addresses. The behaviour is also consistent with MITRE ATT&CK T1027: Obfuscated Files or Information.

First block: clipboard polling and HTTP telemetry

The early block was relatively crude. It:

  • registered a copy event
  • read the clipboard every four seconds and attempted to replace an address
  • created an HTTP request to 84.32.102[.]230:7744 on page load
  • placed the page hostname and path into /p parameters.

Defanged request model:

1
hxxp://84.32.102[.]230:7744/p?h={location.hostname}&u={location.pathname}

There was a catch. The decoded BTC, ETH and TRON replacement strings in this variant were invalid. The BTC string failed Bech32 checksum validation, the ETH value was not a valid 20-byte hexadecimal address, and the TRON value also failed format checks. The code could still corrupt user input and cause a transaction to fail, but it could not reliably redirect funds to a usable wallet.

Was this a test stage, a deployment error, deliberate sabotage or just an incomplete rotation caught by the archive? There is not enough evidence to say. Calling it harmless because the wallet strings were broken would be equally careless. It still modified the clipboard and attempted to send page context to an external host.

Adform later confirmed that, on HTTP pages, this request could reach external infrastructure and disclose the hostname, page path and source/public IP. On HTTPS pages it should have been blocked by browser mixed-content policy. Therefore, the absence of a C2 log is not evidence that the payload was absent. On HTTPS, the network indicator may simply never have appeared.

Second block: an actual clipper

The advanced version no longer waited for Ctrl+C. It:

  • traversed DOM text nodes with TreeWalker
  • inspected input, textarea and contenteditable elements
  • overrode the value setters on HTMLInputElement and HTMLTextAreaElement
  • hooked copy, cut, paste and input events
  • repeated its checks every three seconds
  • attempted to preserve cursor and selection positions after replacement.

Adform crypto clipper attack chain Replacement could occur in displayed text, a form, a programmatic value write or the clipboard.

Ctrl+C was not required. The address could be changed in displayed text, a form field or during a programmatic value write. Copying it again was no guarantee either, because the active page could rewrite it once more.

Values recovered from the advanced block:

NetworkRecovered valueValidationAssessment
Bitcoinbc1qmplg…krrlsvalid Bech32 checksumfunctional replacement address
Ethereum0xE798…c573valid 20-byte address recognised by explorersfunctional replacement address
TRONTW4AgG…nJeinvalid length / checksumnon-functional replacement string in this sample

The code contains a TRON regular expression, but a broken string does not become a wallet because the regex is present. There is no third “confirmed wallet” here. On a blockchain, text that looks convincing is still only text.

C2 infrastructure

84.32.102.230 falls within 84.32.102.0/24. RIPE RDAP shows an IPXO sub-allocated block, while RIPEstat associates it with AS59642 / UAB Cherry Servers. The PTR was ip-84-32-102-230.009.ptr.cherryservers.net.

And this is where attribution stops. Infrastructure context is not an operator identity. A VPS provider does not become part of an operation because someone rented a server there. Lithuanian registration geography does not make the operator Lithuanian either. IP geolocation is not a nationality test, no matter how convenient that conclusion may look on a slide.

I did not actively probe 7744/tcp. Current Shodan InternetDB data showed other open ports but not 7744 that is a later passive snapshot and says nothing about the server state during the incident.

59 hosts still do not mean 59 victims

This distinction matters. Fifty-nine hosts are not the same as 59 confirmed victims. An exact-match URLScan search for the four malicious SHA-256 hashes returned:

  • 83 separate scan observations
  • 59 unique page hostnames with one of the four malicious variants
  • 69 observations across 55 unique hosts with a variant containing functional BTC and ETH replacement addresses
  • 4 hosts where only the early variant with invalid replacement strings was observed
  • a window from 2026-07-26 23:29 UTC to 2026-07-30 09:09 UTC.

How was that established? Static analysis maps every archived SHA-256 to specific behaviour and recovered addresses. The URLScan Search API documentation confirms that the hash field is the SHA-256 of an HTTP response downloaded during the scan. A URLScan screenshot is only context. The technical evidence is the exact response hash showing that the session downloaded a byte-for-byte identical file in the context of that page.

Evidence layerWhat it provesWhat it does not prove
Archived-file SHA-256 and static analysisthe clipboard, DOM, form and wallet-replacement capabilities of that filethat the file was received on a specific page
URLScan hash:<sha256> resultthe scan session downloaded that exact response in the context of the specified hostthat every real visitor received the same response
Combining both layersscan sessions across 55 hosts received a file capable of replacing BTC and ETH addresses with valid valuesthat a handler fired, a user transacted or anyone lost funds

My evidence boundary is simple: URLScan sessions across 55 hosts downloaded a malicious JavaScript variant capable of replacing BTC and ETH addresses with valid operator addresses. I cannot turn that into 55 confirmed victims or claim that the address was actually replaced for a real user on every one of those pages. That would require origin, CDN or browser telemetry and transaction-level confirmation.

Four hosts remain separate: betxchange.com, www.tsarino10.com, www.tsarino11.com and www.tsars92.com. Their exact hashes still identify malicious clipboard and C2 code, but the recovered BTC, ETH and TRON destination strings in that variant did not work. I therefore do not include them in the 55 hosts that received a functional wallet-replacement variant.

Observed hosts included, for example, www.wizzair.com, www.ubs.com, www.keysight.com, www.eataly.com, www.groupon.pl, www.cinema-city.pl, www.mindbank.ai, www.zuora.com, www.kicks.se, and a variety of gambling and low-reputation pages. A broad mixture, to put it mildly. That is the fan-out effect of one shared third-party resource.

The underlying evidence is available as machine-readable files, so nobody has to trust the numbers simply because I put them in bold:

URLScan screenshot of the Mindbank page URLScan captured www.mindbank.ai on 27 July 2026. The malware is not visible in the screenshot the technical evidence is the exact SHA-256 of trackpoint-async.js downloaded in that session. Open the URLScan evidence.

URLScan screenshot of the UBS page URLScan captured a UBS page on 27 July 2026. The s2.adform.net resource in that session had the known 02ff86c7… hash. This is an exposure signal, not proof of stolen funds. Open the URLScan evidence.

The 30 July cache tail

The most interesting passive finding was not another domain but the response headers. In the KICKS URLScan session at 09:09 UTC on 30 July 2026, the exact 02ff86c7… variant was retrieved from s1.matas.se/banners/scripts/st/trackpoint-async.js with:

1
2
3
4
5
cf-cache-status: HIT
age: 245023
cache-control: public, max-age=604800
etag: "2c4f9056952481d2697d4e338b0caaf0"
last-modified: Mon, 27 Jul 2026 12:57:38 GMT

245023 seconds is approximately 2.84 days, while max-age=604800 means seven days. That neatly explains how a known malicious response remained observable after Adform reported stopping central distribution.

URLScan screenshot of the KICKS page and cached Adform resource context The URLScan page image only provides session context. The primary finding is the exact response hash and cache metadata in the network log.

This does not mean “Adform lied and the attack continued”. What we see is a stale edge-cache object, not proof that the threat actor retained access. The IR lesson is straightforward: removing a file at origin is not enough. CDN, custom CNAME and browser caches must be purged, and responders need to establish how long the object could survive at every layer.

Bitcoin wallet

Recovered BTC address:

bc1qmplgt0hcg62jc2guz86wn2sms7tqrsulkkrrls

Mempool snapshot on 8 August 2026:

MetricValue
Transactions81
Total received1.73854478 BTC
Total spent1.73838093 BTC
Balance0.00016385 BTC
Received during the official incident window0.03239306 BTC across 9 inflows

The address was active before the official Adform incident. It received 1.56008485 BTC on 28 July, including one inflow of 1.55751290 BTC, and 1.59736145 BTC was consolidated into bc1qjeky…sglm7 on 29 July in this transaction.

The pattern resembles collection and sweeping, but that is where the conclusion stops. Even if the address is hardcoded into the clipper and operator control is highly likely, individual inflows do not reveal their origin. The large 28 July transaction cannot simply be called “money stolen through Adform” without sender confirmation, wallet telemetry or another independent link.

Ethereum wallet

Recovered ETH address:

0xE7983E69df17079ADb0aD7b3458488Cac0dBc573

The ETH address tells a similar story. It was active before the incident, with public-chain activity visible from 2 July. During the official Adform window, from 2026-07-26 21:49 to 2026-07-27 17:16 UTC, it received:

AssetInflows during the incident window
ETH5.79608215429014 across 25 transactions
USDT2,581.032494 across 14 transfers
USDC1,649.349165 across 5 transfers

Approximately 5.4994 ETH was forwarded to 0xaaa56521…f6dc9 in two transactions on 28 July. Later USDC and USDT outflows are also visible. This is consistent with an active collection wallet. Again, consistent with is not the same as proves.

The chain is also full of zero-value transfers and fake homoglyph tokens pretending to be ETH, USDC or USDT. I excluded them from the totals. Summing everything with a convincing dollar-themed name in an explorer produces a marketing number, not intelligence.

Blockscout also shows that the address currently uses an EIP-7702 delegation to a publicly verified TrustWallet.Biz.v1.0.0 implementation. That describes the smart-account mechanism. By itself, it does not suggest that Trust Wallet, the implementation author or their infrastructure participated in the operation.

What we can say about the operator, and what we cannot

AssessmentConfidenceBasis
The operation was financially motivatedhighthe code deliberately replaces cryptocurrency recipient addresses with hardcoded addresses
A software-distribution / supply-chain path was usedhigha malicious suffix entered the shared Adform tracking file
The operator controlled the BTC and ETH replacement addresseshighthey are embedded as final replacement values and are active
The payload was iterated during the incidenthigharchives show several exact hashes and hook combinations
Commodity rented infrastructure was usedmedium–highdirect IP hosted through Cherry Servers/IPXO, without a domain
The same group operated before Adformmediumboth addresses were active earlier, but no independent campaign link exists
The operator is Lithuanian or connected to Lithuanialow / unsupportedLithuania-registered IP infrastructure is not evidence of operator origin
This is a specific known threat actorinsufficient evidenceno reliable code-reuse, infrastructure or operational overlap with a named cluster

Combined into one analytical profile, HCVX-ADFORM-CLIPPER-2026 currently looks like this:

1
2
3
4
5
6
7
8
Motivation:       financial
Capability:       browser-side JavaScript crypto clipping
Access vector:    compromised third-party distribution path
Operational pace: multiple payload variants within hours
Targeting:        opportunistic downstream exposure selection unknown
Infrastructure:   direct-IP HTTP telemetry, commodity hosting
Attribution:      unattributed
Confidence:       high on behaviour, low on identity

Useful pivots for extending the cluster would include other samples using the same six-byte XOR key, reuse of the same setter-hook implementation, earlier clipper campaigns linked to the wallets, historical TLS/SSH fingerprints for the C2 server, and provider-held ordering or access logs. The last category is unlikely to fall out of a particularly clever Google dork.

Exact searches for the wallets, C2 and XOR key on 8 August 2026 did not reveal an independent link to another named campaign or known actor cluster. That is a normal result. It does not prove there is no connection it simply does not give us permission to invent one.

Threat hunting: where to look

Time window

I would begin with:

1
2026-07-26 21:49 UTC  →  2026-07-27 17:16 UTC

I would not stop at the official incident window. Cache hunting should extend to at least 6 August 2026, because the passively observed object carried a seven-day max-age. Browser-cache artifacts should be examined against the actual endpoint response time, not only the central incident timestamp.

Proxy, SWG, CDN and browser telemetry

Look for:

  • requests to /banners/scripts/st/trackpoint-async.js on s2.adform.net and custom CNAME hosts
  • response-body SHA-256 matches for the four malicious hashes
  • ETag: "2c4f9056952481d2697d4e338b0caaf0"
  • HTTP requests to 84.32.102.230:7744 containing /p?h= and &u=
  • cached copies in endpoints, web archives, service workers and browser-cache artifacts
  • cryptocurrency address entry or payment workflows at the same time, but only where the organisation lawfully collects that telemetry.

Splunk example:

1
2
3
4
5
6
7
8
9
10
11
12
13
(index=proxy OR index=web) earliest="07/26/2026:21:49:00" latest="08/06/2026:23:59:59"
(
  (dest_ip="84.32.102.230" dest_port=7744 uri_path="/p")
  OR uri="*/banners/scripts/st/trackpoint-async.js*"
  OR response_sha256 IN (
    "c03567cac86046a9aa1c1c4b43e0c6de7703b43cf01b3d8229978314afc6e9da",
    "0674a58b224cca2ce840153d6c8d474f29f126f7af5054350ba1572c33233aa3",
    "a04461bbdccb15378182cdf77281ec29628f1c1386ae0fe89b62f359471fdeb6",
    "02ff86c7f9fe609a753ff15bda90baa3c3e0d4a2e559ec4fcf8a3de0954b7c55"
  )
)
| stats count min(_time) as first_seen max(_time) as last_seen
  values(url) values(response_sha256) by src_ip, user, dest_host

Microsoft Defender / Sentinel KQL example:

1
2
3
4
5
6
7
8
9
let start = datetime(2026-07-26 21:49:00Z)
let stop  = datetime(2026-08-06 23:59:59Z)
DeviceNetworkEvents
| where Timestamp between (start .. stop)
| where (RemoteIP == "84.32.102.230" and RemotePort == 7744)
    or RemoteUrl has "/banners/scripts/st/trackpoint-async.js"
| project Timestamp, DeviceName, InitiatingProcessAccountName,
          RemoteIP, RemotePort, RemoteUrl, InitiatingProcessFileName
| order by Timestamp asc

Suricata network rule:

1
2
3
4
5
6
7
alert http $HOME_NET any -> 84.32.102.230 7744 (
  msg:"HECAVEX Adform clipper telemetry attempt"
  flow:established,to_server
  http.uri content:"/p?h=" startswith
  content:"&u=" distance:1
  classtype:trojan-activity sid:420260801 rev:1
)

Static-content hunting

The exact hash is the strongest match, but changing one byte kills it. Repositories, CDN exports and browser caches should therefore also be searched for combinations of behavioural strings.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
rule HECAVEX_Adform_Clipper_2026
{
  meta:
    description = "Detects archived Adform browser crypto-clipper structure"
    author = "HECAVEX"
    date = "2026-08-08"
    tlp = "CLEAR"

  strings:
    $key  = "var _k=[0x4d,0x33,0x77,0x54,0x77,0x30]" ascii
    $c2   = "84.32.102.230:7744" ascii
    $clip = "navigator.clipboard.readText" ascii
    $hook = "Object.getOwnPropertyDescriptor(HTMLInputElement.prototype" ascii
    $walk = "document.createTreeWalker" ascii

  condition:
    filesize < 500KB and 3 of them
}

Treat this YARA rule as a hunting rule, not an automatic production block. A browser API appearing in a file is not a confession. The combination of the key, C2 and DOM-rewrite structure is what makes the signal useful.

If this were my incident response

My order of operations would be:

  1. Preserve retrieved trackpoint-async.js copies with response headers, timestamps and SHA-256 values.
  2. Check origin, CDN, reverse proxy, custom CNAME, service-worker and browser-cache layers.
  3. Purge the object across every cache-key variant, not just one URL.
  4. Review CSP reports and proxy logs for 84.32.102.230:7744.
  5. Identify users and processes involved in cryptocurrency payments or wallet-address administration during the incident window.
  6. Verify transaction recipient addresses through an independent channel, not the field displayed on screen at the time.
  7. Rotate Adform integration credentials and review who could modify the distribution object where the integration is under your control.
  8. Improve third-party JavaScript controls: CSP, Subresource Integrity where technically viable, self-hosting risk assessment and response-integrity monitoring.

Subresource Integrity is not a magical answer for a dynamically updated vendor file. If the hash changes constantly, somebody still has to own the pinning and update process. But “we trust the vendor, so we measure nothing” is not a control either. It is a feeling with an invoice.

IOC summary

TypeIndicatorNote
C284.32.102[.]230:7744defanged HTTP telemetry receiver during the incident
URI/p?h={hostname}&u={path}first-block request model
BTCbc1qmplgt0hcg62jc2guz86wn2sms7tqrsulkkrrlsvalid replacement address
ETH0xE7983E69df17079ADb0aD7b3458488Cac0dBc573valid replacement address
TRONTW4AgGnDc2Pk6YAynCtjCKzoKYWPg7nJeinvalid string in this sample
XOR keyM3wTw0structural hunting signal
ETag"2c4f9056952481d2697d4e338b0caaf0"cached malicious 02ff… response

s2.adform.net is a legitimate Adform domain and served a clean file on 8 August 2026. It is not a malicious domain that belongs on a permanent blocklist. This was a time-bound content compromise, so the combination of time + URL + response hash is far more precise than the hostname alone.

What remains unknown

  • How did the attacker gain the ability to modify the distribution file?
  • Did every customer receive the same variant, or was edge, cookie or regional targeting used?
  • How many real page loads received the malicious body?
  • Which blockchain inflows, if any, can be confirmed as resulting from address replacement?
  • Were the same wallets and setter-hook code used in other campaigns?
  • How many custom CNAME and browser-cache copies survived origin remediation?

Until those questions are answered, I am not assigning a polished threat-actor name. We have enough evidence to say that URLScan sessions across 55 hosts downloaded a variant containing functional BTC and ETH replacement addresses. We do not have 55 confirmed victims. The exact victim count and financial loss are unknown: not zero, but also not a number that can be created by summing the wallet’s complete history and calling it incident impact.

Sources

  1. Adform: Security Incident, update of 5 August 2026
  2. Max Maass: captured trackpoint-async.js sample
  3. Kevin Beaumont: Adform compromised to serve crypto stealer
  4. The Hacker News: Hackers Poison Adform Script
  5. Adform: Custom Naming JavaScript documentation
  6. MITRE ATT&CK T1195.002: Compromise Software Supply Chain
  7. MITRE ATT&CK T1027: Obfuscated Files or Information
  8. RIPE RDAP: 84.32.102.230
  9. Mempool: BTC replacement address
  10. Blockscout: ETH replacement address
  11. EIP-7702: Set Code for EOAs
  12. URLScan exact-hash search for a04461bb…
  13. URLScan cached 02ff86c7… observation

Data snapshot: 8 August 2026. Blockchain balances, explorer labels and passive-search results may change over time.

Follow the research

New research without tracking technology

Subscribe to the language-specific RSS feed or follow Deividas on LinkedIn. HECAVEX uses no advertising trackers or marketing pixels.

This post is licensed under CC BY 4.0 by the author.