In February 2025 attackers took approximately $1.46 billion in Ethereum from Bybit. It is the largest theft in the history of the asset class, and it is on this page rather than in a crypto publication for one reason: the root cause was not a smart contract bug and not a stolen private key. It was a JavaScript file on a web page that had been changed.
Bybit used Safe{Wallet} to manage the wallet in question. The attackers did not attack Bybit at all — they attacked the interface Bybit used, and waited.
The account of the intrusion published by Sygnia and by NCC Group runs roughly as follows. On 4 February a Safe{Wallet} developer's macOS workstation was compromised through social engineering. The following day the attackers reached the AWS environment — not by defeating multi-factor authentication, but by riding a live session token that had already been through it.
Then they waited sixteen days, studying how authentication and token handling worked, before touching anything. On 21 February they modified the JavaScript in the S3 bucket serving the Safe{Wallet} web interface.
The payload contained an activation condition restricting it to one specific Bybit cold wallet. Every other user of the service was served a clean application. When the transaction was signed, the interface displayed something legitimate while what actually reached the signers' hardware devices upgraded the wallet contract to one the attackers controlled.
Two minutes after the transaction went through, they removed the code from the interface.
Work through the usual defences against that timeline and they come apart one by one.
A scanner visiting the site sees clean code — the payload was gone two minutes after it fired, and would not have been served to the scanner anyway. Staging and QA saw the clean application, because the activation condition excluded them. A code review finds nothing, because the change was made in the S3 bucket rather than in a repository. Multi-factor authentication was in place and was never defeated; the session it protected was simply reused.
The only place the attack was ever visible was a real browser, in the one session that mattered, during the few minutes the modified script existed. Nothing that samples, schedules or simulates was ever going to be looking then.
It is worth being straight about what would and would not have helped, because the page is not worth much otherwise.
A Content Security Policy that constrains where scripts may load from would not have blocked this. The scripts came from the origin they were supposed to come from, at the URLs they had always used. No new host appeared. Nor was there any data exfiltration to catch: nothing was sent anywhere, because the theft was a transaction the user signed themselves.
Browsers already tell us the answer. With CSP Integrity, every script a real browser executes is reported to us with a content-addressed fingerprint alongside its URL — so the same address serving different code is a different fingerprint, arriving from the session where it actually ran. We keep a verified copy of each version in the JavaScript archive, which is why the question “what exactly was on the page at 14:00?” has an answer rather than a shrug.
That is the signal in this attack — a known URL, on a trusted origin, serving content it has never served before. It is also why we are building the fingerprint into Script Watch's alerting rather than leaving it as forensic record.
If you take payments rather than custody assets, the vertical is not the point and the sum is not the point. The mechanism is.
An attacker with write access to a file your checkout already loads, who serves the malicious version only to the sessions worth attacking, and who removes it afterwards, is describing an attack on any high-value transaction flow. The Bybit case is the version where somebody has published exactly how it was done, and put a number on it.
You don't need a mature Content Security Policy to start. Script Watch gives you the inventory of what executes on your pages, Data Watch gives you the destinations receiving data from them, and CSP Integrity adds the fingerprint of each script as it ran. One line of code or config to deploy.
Reach out to sales@report-uri.com if you want a demo or a trial with no commitment.
One header. No code. Your script inventory starts populating from the first visitor.
30-day free trial · One header · No code · Cancel anytime
Script Watch will monitor all JavaScript dependencies across your entire site and immediately notify you of any changes. A new JavaScript dependency could be the start of a Magecart attack.
Because Script Watch leverages the browser native Content Security Policy, there is no code or agent to deploy and running in the browser means we analyse your site in real-time as your users are browsing. We don't have the same limitations as external scanning services such as authentication or pay walls, geo-sensitive content or an attacker potentially serving safe content to the crawler.
Data Watch will monitor all of the locations that your webpages are sending data to. If your website starts sending data to a new location, it could be the start of a Magecart attack.
With Script Watch and Data Watch combined, you can monitor for clear indicators that your site has been compromised. Attackers will always want to inject their hostile JavaScript, and they'll always want to exfiltrate their stolen data.
We often find that creating a CSP is the first difficult step that organisations face. Having a complete list of all resource dependencies across your entire site like images, scripts or styles, from both 1st-party and 3rd-party locations, is tough to achieve.
The CSP Wizard was created to solve this problem, and in seven days or less, it can give you a complete list of all resources used across your entire site.
With the list of all resources you use on your site, and our easy-to-use tool, creating a viable Content Security Policy is easier than ever with just a few clicks.
All Content Security Policies will need to be tweaked at some point. New resources may be added to the site or old resources removed, and the policy needs to be updated to reflect those changes and kept up to date.
You can import your existing policy into the CSP Builder and use our fully featured tool to make any changes that you require right there in the UI. When you're done, hit Generate, and the CSP Builder will provide you with your new, updated policy.
Script Watch and Data Watch will allow you to rapidly detect and respond to a Magecart attack and combined, that capability puts you ahead of the field. If you want to take it a step further, Content Security Policy can mitigate a Magecart attack and stop it from even happening.
Deploying an effective Content Security Policy can be difficult, but our CSP Reporting allows you to gather feedback and safely test a policy before deployment. Once deployed, an effective Content Security Policy will block a Magecart attack and stop the hostile JavaScript from even running.
We subscribe to various feeds of Threat Intelligence data, along with managing our own internally generated feeds, to keep apprised of the latest threats that exist online.
Using this Threat Intelligence Data, we can better analyse the sources of JavaScript on your website and detect malicious activity sooner.