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.
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:
| Source | What I checked | Interaction |
|---|---|---|
| Adform statement and documentation | incident window, impact and script deployment model | public reading |
| Gist and Wayback files | static diff, hashes, XOR and behaviour | passive download, not executed |
| URLScan | exact response hashes, response metadata and screenshots | passive search |
| RIPE RDAP / RIPEstat | IP prefix, ASN and registration context | passive lookup |
| Mempool and Blockscout | public BTC and ETH blockchain activity | passive 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:
Times are UTC. The blue accent on the final point represents a cached response, not proven continued attacker access.
| Time UTC | Observation | Assessment |
|---|---|---|
| 2026-07-26 21:49 | First activity according to Adform’s retrospective analysis | official start boundary |
| 2026-07-26 23:29 | Wayback file contains the first block with C2 and invalid wallet values | early or broken stage |
| 2026-07-27 00:00 | More advanced single-block variant appears | DOM, forms and programmatic value hook |
| 2026-07-27 00:41 | Archive contains both blocks | copy, cut, paste, input and polling |
| 2026-07-27 01:00 | Adform detects suspicious activity | containment begins |
| 2026-07-27 17:16 | Adform no longer observes new malicious distribution | end of the central incident window |
| 2026-07-30 09:09 | URLScan receives a known exact-hash variant through s1.matas.se | Cloudflare HIT, stale cached object |
| 2026-08-08 | Current s2.adform.net file matches the clean sample prefix | research 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-256 | First passive timestamp | Content |
|---|---|---|
c03567ca…31a | 07-26 23:29 UTC | first block, HTTP C2, invalid replacement values |
0674a58b…aa3 | 07-27 00:00 UTC | advanced single block, valid BTC/ETH |
a04461bb…eb6 | 07-27 00:41 UTC | both blocks, additional paste and input hooks |
02ff86c7…c55 | 07-27 11:40 UTC | full-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
copyevent - read the clipboard every four seconds and attempted to replace an address
- created an HTTP request to
84.32.102[.]230:7744on page load - placed the page hostname and path into
/pparameters.
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,textareaandcontenteditableelements - overrode the
valuesetters onHTMLInputElementandHTMLTextAreaElement - hooked
copy,cut,pasteandinputevents - repeated its checks every three seconds
- attempted to preserve cursor and selection positions after replacement.
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:
| Network | Recovered value | Validation | Assessment |
|---|---|---|---|
| Bitcoin | bc1qmplg…krrls | valid Bech32 checksum | functional replacement address |
| Ethereum | 0xE798…c573 | valid 20-byte address recognised by explorers | functional replacement address |
| TRON | TW4AgG…nJe | invalid length / checksum | non-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 layer | What it proves | What it does not prove |
|---|---|---|
| Archived-file SHA-256 and static analysis | the clipboard, DOM, form and wallet-replacement capabilities of that file | that the file was received on a specific page |
URLScan hash:<sha256> result | the scan session downloaded that exact response in the context of the specified host | that every real visitor received the same response |
| Combining both layers | scan sessions across 55 hosts received a file capable of replacing BTC and ETH addresses with valid values | that 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:
- summary of all 59 hosts
- strict list of 55 hosts that received a functional BTC and ETH replacement variant
- all 83 exact-hash URLScan sessions, with timestamp, hostname, response SHA-256, payload capability and URLScan result link for every row
- hash-to-capability matrix, identifying the variants with functional BTC and ETH replacement addresses.
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 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.
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:
| Metric | Value |
|---|---|
| Transactions | 81 |
| Total received | 1.73854478 BTC |
| Total spent | 1.73838093 BTC |
| Balance | 0.00016385 BTC |
| Received during the official incident window | 0.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:
| Asset | Inflows during the incident window |
|---|---|
| ETH | 5.79608215429014 across 25 transactions |
| USDT | 2,581.032494 across 14 transfers |
| USDC | 1,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
| Assessment | Confidence | Basis |
|---|---|---|
| The operation was financially motivated | high | the code deliberately replaces cryptocurrency recipient addresses with hardcoded addresses |
| A software-distribution / supply-chain path was used | high | a malicious suffix entered the shared Adform tracking file |
| The operator controlled the BTC and ETH replacement addresses | high | they are embedded as final replacement values and are active |
| The payload was iterated during the incident | high | archives show several exact hashes and hook combinations |
| Commodity rented infrastructure was used | medium–high | direct IP hosted through Cherry Servers/IPXO, without a domain |
| The same group operated before Adform | medium | both addresses were active earlier, but no independent campaign link exists |
| The operator is Lithuanian or connected to Lithuania | low / unsupported | Lithuania-registered IP infrastructure is not evidence of operator origin |
| This is a specific known threat actor | insufficient evidence | no 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.jsons2.adform.netand custom CNAME hosts - response-body SHA-256 matches for the four malicious hashes
ETag: "2c4f9056952481d2697d4e338b0caaf0"- HTTP requests to
84.32.102.230:7744containing/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:
- Preserve retrieved
trackpoint-async.jscopies with response headers, timestamps and SHA-256 values. - Check origin, CDN, reverse proxy, custom CNAME, service-worker and browser-cache layers.
- Purge the object across every cache-key variant, not just one URL.
- Review CSP reports and proxy logs for
84.32.102.230:7744. - Identify users and processes involved in cryptocurrency payments or wallet-address administration during the incident window.
- Verify transaction recipient addresses through an independent channel, not the field displayed on screen at the time.
- Rotate Adform integration credentials and review who could modify the distribution object where the integration is under your control.
- 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
| Type | Indicator | Note |
|---|---|---|
| C2 | 84.32.102[.]230:7744 | defanged HTTP telemetry receiver during the incident |
| URI | /p?h={hostname}&u={path} | first-block request model |
| BTC | bc1qmplgt0hcg62jc2guz86wn2sms7tqrsulkkrrls | valid replacement address |
| ETH | 0xE7983E69df17079ADb0aD7b3458488Cac0dBc573 | valid replacement address |
| TRON | TW4AgGnDc2Pk6YAynCtjCKzoKYWPg7nJe | invalid string in this sample |
| XOR key | M3wTw0 | structural 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
- Adform: Security Incident, update of 5 August 2026
- Max Maass: captured
trackpoint-async.jssample - Kevin Beaumont: Adform compromised to serve crypto stealer
- The Hacker News: Hackers Poison Adform Script
- Adform: Custom Naming JavaScript documentation
- MITRE ATT&CK T1195.002: Compromise Software Supply Chain
- MITRE ATT&CK T1027: Obfuscated Files or Information
- RIPE RDAP:
84.32.102.230 - Mempool: BTC replacement address
- Blockscout: ETH replacement address
- EIP-7702: Set Code for EOAs
- URLScan exact-hash search for
a04461bb… - 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.
