CVE-2026-115893 is a Wasmtime sandbox-escape vulnerability that affects Arm64 systems using the default Cranelift compiler backend. A user-controlled WebAssembly module can abuse an unusually large br_table instruction so the generated native code branches to the wrong target, potentially crossing the boundary between an isolated guest and its host process.
The Bytecode Alliance published the underlying security advisory on October 19, 2026. The CVE record followed on October 23, and the OSV entry was modified on October 28. Operators should treat this as an architecture-specific runtime issue: the highest priority is any Arm64 or aarch64 service that accepts WebAssembly from tenants, plugins, users, build jobs, or automation pipelines.
What goes wrong inside Cranelift
WebAssembly’s br_table instruction represents a multi-way branch. A runtime compiler must translate its target table into safe native machine code while preserving WebAssembly’s control-flow rules. According to the maintainer advisory, an Arm64 build with more than roughly 256,000 targets in one table can be lowered with an incorrect conditional branch target.
The bad branch can jump to other code at an offset influenced by the module. That breaks a central Wasmtime security assumption: untrusted guest code should remain constrained by the runtime’s sandbox. The advisory describes arbitrary sandbox escape as the possible outcome and assigns a critical severity rating. This article uses the vendor’s published score and does not invent a separate one.
The flaw is not a general WebAssembly language weakness. It is a code-generation error in the Cranelift backend on aarch64. That distinction matters for triage because architecture, compiler backend, runtime version, and module trust boundary all change practical exposure.
Affected versions and fixed branches
| Wasmtime line | Affected range | Fixed destination |
|---|---|---|
| 36.x maintenance line | Earlier than 36.0.19 | 36.0.19 or later in the line |
| 37.x through 48.x | 37.0.0 through versions earlier than 48.0.7 | 48.0.7 or later |
| 49.x | 49.0.0 through 49.0.3 | 49.0.4 or later |
| Older releases with Arm64 support | Affected according to the maintainer | Move to a supported fixed release |
Wasmtime 36.0.19, 48.0.7, and 49.0.4 were released with the fix. The project also lists version 50.0.0 after those security releases. Select a supported branch that fits your application’s compatibility requirements rather than jumping between major versions without testing. Distribution packages may use backported patches, so compare the package advisory and build revision instead of relying only on the upstream semantic version.
Decide whether a workload is exposed
Confirm the host architecture
The published vulnerable path is specific to aarch64, commonly reported by Linux tools as aarch64 or arm64. Check the node that performs compilation and execution, not only the developer workstation or CI controller.
uname -m
dpkg --print-architecture 2>/dev/null
rpm --eval '%{_arch}' 2>/dev/null
docker image inspect --format '{{.Architecture}}' IMAGE:TAGFind the real Wasmtime version
Wasmtime may appear as a command-line binary, a Rust crate, a vendored component, a language binding, or part of a larger platform. Inventory the deployed artifact and its lockfile or software bill of materials. A safe host binary does not prove that every container or statically linked service uses the same runtime.
wasmtime --version
cargo tree -i wasmtime
cargo metadata --format-version 1 --locked > cargo-metadata.json
rg 'name = "wasmtime"|version = ' Cargo.lock
# For a running container
docker exec CONTAINER wasmtime --version
docker inspect --format '{{.Image}} {{.Config.Image}}' CONTAINERMap the trust boundary
Prioritize services that compile or run modules supplied outside the runtime’s administrative trust domain. Examples include plugin platforms, edge-compute workers, multi-tenant function services, policy engines, package analysis systems, CI jobs, and developer tools that preview uploaded modules. A service that executes only pinned, reviewed modules has a lower immediate exposure, but it still needs the fixed runtime because module provenance and deployment behavior can change.
- Record who can submit or replace a module.
- Identify whether modules arrive over a network, registry, repository, or shared storage path.
- Confirm whether the engine uses Cranelift or a product-specific backend.
- Document the host architecture for every replica and autoscaling pool.
- Capture the deployed image digest, package revision, and runtime configuration.
Mitigation and patch sequence
- Pause or restrict untrusted module submission on affected Arm64 pools.
- Preserve current image digests, runtime versions, lockfiles, and configuration before changing the environment.
- Upgrade to 36.0.19, 48.0.7, 49.0.4, or a later supported release containing the fix.
- Rebuild statically linked applications and container images so the corrected crate is actually deployed.
- Roll out through a canary pool, exercise representative modules, and verify isolation controls.
- Replace every affected replica and confirm that autoscaling templates no longer reference an old image.
Temporarily moving untrusted workloads to a fixed x86_64 pool, disabling module uploads, or accepting only signed and approved modules can reduce exposure while patching proceeds. These are containment measures, not repairs. They also require careful checks for queue backlogs, tenant isolation, and accidental fallback to an affected Arm64 node.
For Kubernetes deployments, inspect node architecture labels, affinity rules, runtime images, and DaemonSet or operator-managed components. The site’s Kubernetes node-audit checklist provides a reusable pattern for validating node attributes before a fleet change. If guest modules can access shared host paths, also review the shared-filesystem isolation analysis so a runtime patch is not mistaken for complete workload isolation.
Hands-on lab: triage a mixed Wasmtime inventory
This lab is deliberately non-exploitative. It reads a local CSV and classifies systems by architecture, backend, module trust, and published fixed-version floor. It does not download, compile, or execute WebAssembly.
Prerequisites and isolated environment
- Python 3.9 or later.
- An empty directory on an analyst workstation or disposable VM.
- An inventory containing no credentials, tokens, or tenant data.
Create inventory.csv:
asset,architecture,backend,accepts_untrusted_wasm,version
edge-arm,arm64,cranelift,yes,49.0.3
worker-arm,aarch64,cranelift,no,48.0.6
build-x86,x86_64,cranelift,yes,49.0.3
arm-alt,arm64,winch,yes,49.0.3
fixed-arm,arm64,cranelift,yes,49.0.4
old-arm,aarch64,cranelift,yes,36.0.18Save the following as wasmtime_inventory.py:
#!/usr/bin/env python3
import csv, sys
def vt(value):
try: return tuple(int(x) for x in value.lstrip("v").split(".")[:3])
except ValueError: return None
def version_state(value):
v = vt(value)
if not v or len(v) != 3: return "MANUAL_REVIEW", "unparseable version"
major = v[0]
if major < 36: return "UPDATE", "all earlier Arm64 releases are affected"
if major == 36: floor = (36, 0, 19)
elif 37 <= major < 48: return "UPDATE", "37.x through 47.x are affected"
elif major == 48: floor = (48, 0, 7)
elif major == 49: floor = (49, 0, 4)
else: return "CURRENT", "newer than published fixed branches"
return (("UPDATE", "fixed floor is " + ".".join(map(str, floor)))
if v < floor else
("CURRENT", "meets fixed floor " + ".".join(map(str, floor))))
def assess(row):
arch = row["architecture"].lower()
if arch not in {"arm64", "aarch64"}:
return "NOT_MATCHING_ARCH", "advisory scope is Arm64/aarch64"
if row["backend"].lower() != "cranelift":
return "MANUAL_REVIEW", "confirm backend and product-specific exposure"
state, detail = version_state(row["version"])
if state == "UPDATE" and row["accepts_untrusted_wasm"].lower() == "yes":
return "UPDATE_HIGH", detail
if state == "UPDATE": return "UPDATE_LOWER_EXPOSURE", detail
return state, detail
print("asset,version,status,detail")
with open(sys.argv[1], newline="", encoding="utf-8") as handle:
for row in csv.DictReader(handle):
status, detail = assess(row)
print(f'{row["asset"]},{row["version"]},{status},{detail}')Run the audit:
python3 wasmtime_inventory.py inventory.csvExpected output
asset,version,status,detail
edge-arm,49.0.3,UPDATE_HIGH,fixed floor is 49.0.4
worker-arm,48.0.6,UPDATE_LOWER_EXPOSURE,fixed floor is 48.0.7
build-x86,49.0.3,NOT_MATCHING_ARCH,advisory scope is Arm64/aarch64
arm-alt,49.0.3,MANUAL_REVIEW,confirm backend and product-specific exposure
fixed-arm,49.0.4,CURRENT,meets fixed floor 49.0.4
old-arm,36.0.18,UPDATE_HIGH,fixed floor is 36.0.19A NOT_MATCHING_ARCH result applies only to this specific advisory and is not a general security verdict. MANUAL_REVIEW exists because embedded products and alternate backends may carry different risk or vendor guidance.
Troubleshooting and cleanup
- If the script reports missing columns, confirm the CSV header exactly matches the example.
- If a distribution version includes suffixes, record its package release and consult the distribution security tracker.
- If Wasmtime is statically linked, use the build lockfile, SBOM, or binary provenance rather than a host package query.
- If the backend is unknown, do not assume Cranelift or declare the service safe.
rm -f inventory.csv wasmtime_inventory.py cargo-metadata.jsonDetection and post-upgrade validation
The maintainer advisory does not provide network indicators or a malicious module hash. Monitor for unexpected Wasmtime host crashes, illegal-instruction or segmentation-fault events, abnormal JIT compilation failures, sandbox policy alerts, and unusual large modules submitted to exposed services. None of these signals proves exploitation, so correlate them with module provenance, authentication records, request timing, runtime version, architecture, and crash telemetry.
If suspicious activity predates the upgrade, preserve the module bytes and hash without executing them, capture the affected image digest and process metadata, and follow the product’s incident-response procedure. A sandbox escape can affect the host process, so investigation should extend beyond the guest’s expected files and logs.
- Confirm every Arm64 replica reports a fixed build.
- Verify the new container image digest is present in deployment templates and registries.
- Run known-good module regression tests through the same compiler path.
- Test guest resource limits, filesystem permissions, network policies, and syscall controls.
- Confirm rollback images do not reintroduce the vulnerable runtime.
Conclusion
CVE-2026-115893 shows why a sandbox is only as strong as the native code generated beneath it. The practical response is to find Arm64 Wasmtime deployments, identify Cranelift-backed services that accept untrusted modules, move them to a fixed branch, rebuild every embedded artifact, and validate both runtime functionality and surrounding host controls. Architecture-aware inventory is the difference between a precise response and a noisy fleet-wide guess.
Primary sources
- Bytecode Alliance Wasmtime advisory GHSA-mghf-wjfp-p5xm, published October 19, 2026.
- Wasmtime security releases, including 36.0.19, 48.0.7, and 49.0.4.
- OSV record for CVE-2026-115893, published October 23 and modified October 28, 2026.
- RustSec advisory RUSTSEC-2026-0379.
- Debian security tracker for distribution package status.
- Ubuntu security notice for distribution-specific status.







