The security model of WebAssembly has two important goals: (1) protect users from buggy or malicious modules, and (2) provide developers with useful primitives and mitigations for developing safe applications, within the constraints of (1).
Each WebAssembly module executes within a sandboxed environment separated from the host runtime using fault isolation techniques. This implies:
Additionally, each module is subject to the security policies of its embedding. Within a web browser, this includes restrictions on information flow through same-origin policy. On a non-web platform, this could include the POSIX security model.
The design of WebAssembly promotes safe programs by eliminating dangerous features from its execution semantics, while maintaining compatibility with programs written for C/C++.
Modules must declare all accessible functions and their associated types at load time, even when dynamic linking is used. This allows implicit enforcement of control-flow integrity (CFI) through structured control-flow. Since compiled code is immutable and not observable at runtime, WebAssembly programs are protected from control flow hijacking attacks.
Variables in C/C++ can be lowered to two different primitives in WebAssembly,
depending on their scope. Local variables
with fixed scope and global variables are
represented as fixed-type values stored by index. The former are initialized
to zero by default and are stored in the protected shadow stack, whereas
the latter are located in the global index space
and can be imported from external modules. Local variables with
unclear static scope (e.g. are used by the address-of
operator, or are of type
struct and returned by value) are stored in a separate
user-addressable stack in linear memory at
compile time. This is an isolated memory region with fixed maximum size that is
zero initialized by default. References to this memory are computed with
infinite precision to avoid wrapping and simplify bounds checking. In the future,
support for multiple linear memory sections and
finer-grained memory operations
(e.g. shared memory, page protection, large pages, etc.) will be implemented.
Compared to traditional C/C++ programs, these semantics obviate certain classes of memory safety bugs in WebAssembly. Buffer overflows, which occur when data exceeds the boundaries of an object and accesses adjacent memory regions, cannot affect local or global variables stored in index space, they are fixed-size and addressed by index. Data stored in linear memory can overwrite adjacent objects, since bounds checking is performed at linear memory region granularity and is not context-sensitive. However, the presence of control-flow integrity and protected shadow call stacks prevents direct code injection attacks. Thus, common mitigations such as data execution prevention (DEP) and stack smashing protection (SSP) are not needed by WebAssembly programs.
Another common class of memory safety errors involves unsafe pointer usage and
undefined behavior. This includes dereferencing
pointers to unallocated memory (e.g.
NULL), or freed memory allocations. In
WebAssembly, the semantics of pointers have been eliminated for function calls
and variables with fixed static scope, allowing references to invalid indexes in
any index space to trigger a validation error at load time, or at worst a trap
at runtime. Accesses to linear memory are bounds-checked at the region level,
potentially resulting in a trap at runtime. These memory region(s) are isolated
from the internal memory of the runtime, and are set to zero by default unless
Nevertheless, other classes of bugs are not obviated by the semantics of WebAssembly. Although attackers cannot perform direct code injection attacks, it is possible to hijack the control flow of a module using code reuse attacks against indirect calls. However, conventional return-oriented programming (ROP) attacks using short sequences of instructions (“gadgets”) are not possible in WebAssembly, because control-flow integrity ensures that call targets are valid functions declared at load time. Likewise, race conditions, such as time of check to time of use (TOCTOU) vulnerabilities, are possible in WebAssembly, since no execution or scheduling guarantees are provided beyond in-order execution and post-MVP atomic memory primitives . Similarly, side channel attacks can occur, such as timing attacks against modules. In the future, additional protections may be provided by runtimes or the toolchain, such as code diversification or memory randomization (similar to address space layout randomization (ASLR)), bounded pointers (“fat” pointers), or finer-grained control-flow integrity.