WebAssembly (WASM) now runs inside every major browser, powers edge-compute platforms like Cloudflare Workers and Fastly Compute, and increasingly ships as prebuilt .wasm binaries inside npm, crates.io, and PyPI packages. On February 11, 2018, that reach became a liability: attackers compromised the Browsealoud accessibility plugin and used it to inject Coinhive's WebAssembly-based Monero-mining script into more than 4,275 websites in a single day, including the UK's Information Commissioner's Office, the NHS, and several U.S. federal court sites. WASM's sandbox is real, but it is not a security cure-all — a 2020 USENIX Security study found that memory-corruption bugs in C/C++ source code survive the trip to WebAssembly almost intact, because compiled .wasm binaries typically ship without stack canaries, ASLR, or DEP. This post breaks down where WASM risk actually lives: inside the module, inside the browser engine, across the supply chain, and in the growing world of server-side WASI runtimes.
Does compiling code to WebAssembly make memory-corruption bugs disappear?
No. WASM's sandbox stops a compromised module from reading or writing memory outside its own linear memory region, but it does nothing to prevent corruption inside that region. Researchers Daniel Lehmann, Johannes Kinder, and Michael Pradel demonstrated this in "Everything Old Is New Again: Binary Security of WebAssembly" (USENIX Security 2020): they took a set of real-world CVEs in C/C++ libraries, recompiled the vulnerable code to WASM with Emscripten, and found the exploits still worked. A classic stack-based buffer overflow that would trigger a canary check and crash on native x86 instead silently overwrote adjacent WASM globals or the function table, because Emscripten-era binaries commonly omitted stack canaries, ASLR, and W^X protections by default. The practical result: an attacker who finds a heap overflow in a WASM-compiled image or video codec can still hijack the module's internal control flow — the equivalent of a return-oriented-programming chain, just fenced inside the sandbox rather than fenced out of it.
Can malicious WebAssembly actually break out of the browser sandbox?
Yes, when the bug lives in the engine implementing the sandbox rather than in the WASM code itself. WebAssembly and JavaScript in Chrome, Firefox, and Safari share the same underlying JIT infrastructure, so a compiler bug reachable from either language can compromise the host, not just the module. Apple's Safari 11.1 update in March 2018 patched CVE-2018-4192, a WebKit memory-corruption issue in its WebAssembly implementation that could lead to arbitrary code execution. More broadly, Chrome's V8 team has repeatedly shipped emergency, in-the-wild patches for type-confusion bugs in the same engine that executes WASM — CVE-2021-30632 and CVE-2022-1096 among them — underscoring that the sandbox's guarantees are only as strong as the engine enforcing them. This is why browser vendors treat WASM compiler and validator code as a top attack surface for their own bug-bounty and fuzzing programs, not a solved problem.
Did a WebAssembly cryptominer really infect thousands of government websites?
Yes, and it remained one of the most disruptive real-world WASM incidents on record. On February 11, 2018, a researcher (Scott Helme) and the UK's National Cyber Security Centre confirmed that attackers had modified the Browsealoud script — a third-party accessibility plugin from Texthelp embedded on thousands of sites — to load Coinhive's WebAssembly Monero-mining code into every visiting browser. Because Browsealoud was pulled in via a single external <script> tag with no subresource integrity check, the tampering propagated instantly to every site that embedded it: over 4,275 websites, including the UK Information Commissioner's Office, the NHS, the UK's Student Loans Company, and multiple U.S. federal court domains. Check Point's Global Threat Impact Index ranked Coinhive as the single most prevalent malware family worldwide for over a year following its September 2017 launch. Coinhive itself shut down on March 8, 2019, citing the crashing price of Monero and browser vendors adding built-in mining-script blocklists — but the incident remains the clearest demonstration that WASM's performance advantages (near-native execution speed for hashing algorithms) are exactly what makes it attractive for abuse, not just legitimate use.
Does WebAssembly create a blind spot in software supply chain security?
Yes, because a compiled .wasm binary is opaque to tools built to read source code and package manifests. Popular npm packages like sql.js (SQLite compiled to WASM) and argon2-browser, along with Rust crates targeting wasm32-wasi and modules published to registries like wapm.io, ship functionality as prebuilt binary blobs rather than readable source. If one of those binaries embeds a vulnerable version of a C library — an old zlib or libpng, for example — the CVE travels with it, but a software composition analysis tool that only fingerprints package.json, Cargo.toml, or JavaScript source strings has nothing to match against, because compilation typically strips the symbols and version strings a scanner would look for. That gap is compounded by CDN delivery: a site pulling a .wasm file from a third-party CDN at runtime (as Browsealoud did with its script) can have its dependency swapped out entirely between deploys, with no lockfile entry ever changing.
What extra risk comes from running WebAssembly outside the browser?
The main risk is over-permissioned WASI capabilities and unpatched runtime bugs, since server-side WASM runs with fewer of the browser's built-in guardrails. Platforms like Cloudflare Workers, Fastly Compute, and Shopify Functions execute untrusted, multi-tenant third-party WASM modules using runtimes such as Wasmtime and Wasmer; both projects maintain public GitHub Security Advisory databases and have each published dozens of advisories since 2020 for out-of-bounds memory access in operations like table.copy and linear-memory growth. WASI's capability model is designed to be deny-by-default — a module should only get the specific file descriptors, directories, or network sockets the host explicitly grants — but that protection collapses the moment a host preopens a broader directory or socket range than the workload actually needs, which is the WASM equivalent of an over-scoped IAM role. Because these runtimes are typically invoked as a dependency inside a larger service rather than pinned and tracked like a direct package, they're an easy candidate to fall out of patch cadence.
How can security teams reduce their WebAssembly attack surface today?
Start by treating every .wasm binary as a first-class, versioned dependency rather than an opaque asset. Concretely: apply Content-Security-Policy restrictions (avoid blanket 'wasm-unsafe-eval' grants) and Subresource Integrity hashes on any WASM fetched from a third-party CDN, exactly the control that would have blocked the Browsealoud compromise; pin and patch WASI runtimes like Wasmtime and Wasmer on the same cadence as any other production dependency and subscribe to their GHSA feeds; scope WASI capabilities to the narrowest preopened directories and sockets a module needs, never a shared root; and monitor CPU and egress patterns for the sustained, low-and-slow spikes characteristic of cryptojacking. None of this works, though, if the organization can't first see which services actually load a .wasm module and which of those code paths are reachable from untrusted input.
How Safeguard Helps
Safeguard closes the visibility gap that lets WASM slip past traditional SCA tooling. Our SBOM generation and ingest pipeline treats compiled .wasm binaries as first-class components — fingerprinting embedded library versions rather than relying on stripped symbol tables — so a vulnerable zlib or libpng compiled into a module surfaces the same way a vulnerable npm package would. Reachability analysis then determines whether that vulnerable code path inside the module is actually invoked from an exposed API or untrusted input, cutting through the noise of theoretical CVEs in code nobody calls. Griffin AI correlates that reachability signal with runtime and dependency context to prioritize the handful of findings that represent real exploitability, and where a fix exists — a patched runtime version, an updated crate, or a safer compilation flag — Safeguard opens an auto-fix pull request so the team can ship the remediation without a manual triage cycle.