WebAssembly has been one of the trendiest intermediate representations since a while.
However, its definition of safety means preventing breaching the sandbox. Its goal is to prevent escalation from the VM guest code to the VM host boundary.
WASI then defines a capabilities-based syscall interface that can be used by applications. Some alternatives which can be implemented with running native code are through using seccomp on Linux. (or using dkmon on Windows)
In WebAssembly, only one memory segment is allowed. As such, unlike managed language runtimes (such as Java and the CLR), WebAssembly by itself does not provide memory safety.
Each global variable gets its own memory segment however, as do local variables. A memory allocation on the heap means that you lose those thin guarantees.
Recompiling C or C++ code to WebAssembly does not make it any more secure, unlike recompiling it for .NET with /clr:safe or to CHERI hardware which provide those possibilities by design, which are always used.
(ASAN, because of its performance overhead even when it’s present, doesn’t cover those issues in practice, you can’t afford to have it always on)
This also means that a suboptimal translation from .NET to WebAssembly is done, as memory segment information could have been used to elide some of those checks at runtime.
However, if your language has some extent of memory safety like Rust, using WebAssembly doesn’t degrade those.
TL;DR: WebAssembly is a sandbox isolating the program from the underlying machine. It doesn’t aim to provide safety properties for that program, and doesn’t try to.