
Structured reference of Chrome browser exploit mitigations. First published in the research article Chrome Exploit Mitigations, which includes narrative discussion of MiraclePtr, v8 sandbox, and PartitionAlloc in context.
Chrome has many exploit mitigations that are doing more work than public knowledge suggests.
The tables below are actual as of Stable (M148).
| Mitigation | Details | Enabled? | OS | Bypass |
|---|---|---|---|---|
| PartitionAlloc-Everywhere | PA-E routes every renderer and browser allocation through PartitionRoot via the allocator shim, controlled by use_partition_alloc_as_malloc_default and implemented under base/allocator/partition_allocator/. | Default on | All | — |
| Bucketed slot spans | Each partition splits allocations into size-class buckets (PartitionBucket in partition_bucket.cc); requests round up to the bucket's slot_size and slots come from num_system_pages_per_slot_span system pages, isolating size classes from one another. | Default on | All | Partial |
| Address-pool isolation | On 64-bit, PartitionAddressSpace reserves separate virtual-address pools by purpose — regular (kRegularPoolHandle), BRP (kBRPPoolHandle), configurable, and thread-isolated — collectively known as the giga-cage / gigacage. | Default on | 64-bit | Partial |
| Out-of-cage metadata | With move_metadata_outside_gigacage, per-slot metadata (refcounts and tags held in InSlotMetadata / InSlotMetadataTable) lives in a second mapping outside the giga-cage, so in-cage write primitives can't reach it. | Default on | 64-bit non-iOS | Partial |
| Freelist pointer encoding | The freelist next pointer is obfuscated by EncodedNextFreelistEntry::Transform() — ReverseBytes() on little-endian, negation on big-endian — and cross-checked against a shadow copy at a different offset, raising the bar for tcache-style freelist poisoning. | Default on | All | Yes |
| Thread Cache | ThreadCache keeps a per-thread, TLS-backed freelist of recently-freed slots (up to kThreadCacheDefaultSizeThreshold) in front of the central per-bucket freelist; instances coordinate via ThreadCacheRegistry, are sized by SetThreadCacheMultiplier, and drained by RunPeriodicPurge. The same hot path hosts cacheline poisoning, tombstone validation, and SchedulerLoopQuarantine integration (kThreadCacheQuarantineIndex) — added because real-world exploits target tcache/fastbin-style freelist corruption. See base/allocator/partition_allocator/src/partition_alloc/thread_cache.h. | Default on | All | Subsystem — sub-features bypassed individually |
| Cacheline poisoning on free | On free() into the Thread Cache, the cacheline holding the new freelist next is overwritten with poison_16_bytes (0xbadbad00 repeating) so a subsequent UAF read on that line crashes early instead of returning attacker-shaped data; gated by PA_CONFIG(HAS_FREELIST_SHADOW_ENTRY). See thread_cache.h:626-674. | Default on (with shadow entry, LE) | All | Probabilistic — only the touched cacheline |
| ThreadCache tombstone | After a thread exits, its per-thread ThreadCache* is marked with kTombstoneMask low bits; IsValidPtr / IsValid check for the tombstone and reject the access before dereference, preventing use-after-thread-exit on the cache pointer. See thread_cache.h:279-298. | Default on | All | Limited |
| Freelist randomization | Per-bucket randomization of free-entry order would make grooming the freelist harder, but no such shuffle is implemented in M148. | Not found in M148 | — | — |
| Guard pages | Unmapped guard pages flank slot spans and direct maps (DirectMapGuardPages in partition_page.h) so a linear overflow off the end of a slot faults rather than corrupting adjacent metadata. | Default on | All | Partial |
| Partition cookie | A 16-byte canary 0xDE 0xAD 0xBE 0xEF 0xCA 0xFE 0xD0 0x0D 0x13 0x37 0xF0 0x05 0xBA 0x11 0xAB 0x1E (kCookieValue in partition_cookie.h) is stamped at the end of every allocation via PartitionCookieWriteValue; on free, PartitionCookieCheckValue verifies the pattern and calls CookieCorruptionDetected on mismatch. Gated by USE_PARTITION_COOKIE (use_partition_cookie), enabled only in debug / DCHECK builds. | Debug / DCHECK only | All | Limited |
| MiraclePtr | MiraclePtr — also called BRP, BackupRefPtr, or raw_ptr<T> (with raw_ref<T> for references) — wraps non-owning pointer fields; BackupRefPtrImpl increments a refcount in InSlotMetadata and, on free() with a non-zero count, quarantines the slot via request_quarantine and poisons the memory with internal::kQuarantinedByte = 0xEF (so reads return the famous 0xEFEFEFEFEFEFEFEF pattern), turning a UAF into a crash. Gated by kPartitionAllocBackupRefPtr; fields opt out with RAW_PTR_EXCLUSION. | Default on (Android renderer excluded) | All | No bypass of invariant |
| Dangling-pointer detector | When a slot is freed while a raw_ptr<T> still points at it, DanglingPointerDetector raises a DanglingRawPtrChecks failure in DCHECK/debug builds; enable_dangling_raw_ptr_checks_default gates the build, and DanglingUntriaged tags known-but-unaddressed cases. Debug builds (EXPENSIVE_DCHECKS_ARE_ON) also DebugMemset freed slots with kFreedByte = 0xCD and stamp kUninitializedByte = 0xAB on freshly recommitted memory. | Debug / DCHECK only | Linux/CrOS | — |
| PCScan | The briefly-shipped conservative-scanning quarantine — also called *Scan / StarScan — has been removed from M148; no references remain. | Removed | — | — |
| GWP-ASan | enable_gwp_asan_support puts a guard page around a tiny sampled fraction of allocations so heap bugs occasionally crash deterministically and bucket together in crash reports; detection only, not prevention. | Default on (low rate) | All | — |
| Scheduler-loop quarantine | SchedulerLoopQuarantine defers the actual free() until a later scheduler-loop tick so reuse can't happen on the freeing thread's hot path; quarantined memory is poisoned with 0xcdcdcdcd; per-process configuration is JSON-driven and the feature is off by default. | Opt-in | All | New |
| Advanced checks | kPartitionAllocAdvancedChecks (AdvancedChecks) turns on extra runtime integrity assertions, enabled per process (browser / renderer / GPU / non-renderer / all); off by default. | Opt-in | All | New |
| Memory reclaimer | PartitionAllocMemoryReclaimer periodically decommits idle slot spans to reclaim address-space fragmentation. | Default on | All | — |
| Straighten/sort freelist | StraightenLargerSlotSpanFreeLists and SortSmallerSlotSpanFreeLists reorder per-span freelists on purge to improve allocation locality. | Default on | All | — |
| Shadow metadata | EnableShadowMetadata maps PartitionAlloc metadata twice — read-only to the allocator's normal code, and writable behind a PKU key — so corruption from a write primitive in regular code cannot reach metadata. HW-gated. | Default on (HW-gated) | x64 Linux/CrOS | New |
| Thread-isolation pool | A dedicated partition pool (kThreadIsolatedPoolHandle, PA_THREAD_ISOLATED_ALIGN) for sensitive allocations whose pages are guarded by Intel MPK / PKU keys (enable_pkeys); only threads holding the key can write. | Default on (HW-gated) | x64 Linux/CrOS | Yes (PKU) |
| PartitionAlloc MTE | On ARM hardware with MTE, PartitionAllocMTE / kEnableMemoryTaggingChecks tags each slot and matches the tag on access in sync or async mode; mismatched tags fault. | Default on (HW-gated) | Android arm64 | Yes |
| Strict free-size check | kPartitionAllocFreeWithSize enables PartitionRoot::FreeWithSize to verify that the caller-passed size on free matches the slot's actual size, catching size-class confusion and type-confused frees. | Opt-in | All | New |
| ASan-BRP integration | ASan-only checks (kAsanBrpDereferenceCheck, kAsanBrpExtractionCheck, kAsanBrpInstantiationCheck) instrument raw_ptr<T> dereference, extraction, and instantiation against BRP-protected memory to surface misuse during sanitizer runs. | ASan builds only | All | N/A (sanitizer) |
| Mitigation | Details | Enabled? | OS | Bypass |
|---|---|---|---|---|
| V8 Sandbox | The V8 heap sandbox (a.k.a. heap cage) is a 4 GB virtual address range set up by Sandbox::Initialize() in v8/src/sandbox/sandbox.h and gated by v8_enable_sandbox / V8_ENABLE_SANDBOX; all V8 on-heap pointers must point inside it, and stray out-of-cage references are caught by SBXCHECKs. | Default on | 64-bit non-Fuchsia | Yes |
| Pointer compression | Inside the cage, V8 stores pointers as 32-bit cage-relative tagged values (V8_COMPRESS_POINTERS); v8_enable_pointer_compression / _shared_cage and kPtrComprCageBaseAlignment define the shared base alignment. | Default on | x64 / arm64 / loong64 | Foundational |
| External Pointer Table (EPT) | Raw host pointers held by V8 objects ("sandboxed pointers") live in ExternalPointerTable outside the cage and are referenced from inside via tagged handles (kExternalPointerTagShift). See v8/src/sandbox/external-pointer-table.h. | Default on (with sandbox) | All | Yes |
| Code Pointer Table (CPT) | JSFunction::code is indirected through CodePointerTable via a kCodePointerHandle, so a corrupted handle can only resolve to an existing compiled code object rather than an arbitrary address. See v8/src/sandbox/code-pointer-table.h. | Default on (with sandbox) | All | Yes |
| Wasm Code Pointer Table (WCPT) | The Wasm analog of CPT: WasmCodePointerTable stores a signature_hash per entry that's cross-checked at indirect Wasm calls, and the table itself is pkey-write-protected on supported HW. See v8/src/wasm/wasm-code-pointer-table.h. | Default on (with sandbox) | All | Yes |
| Trusted Pointer Table (TPT) | TrustedPointerTable holds pointers to V8-internal trusted objects, dispatched through 15-bit IndirectPointerTags so a corrupted handle can only name a same-type trusted entry. See v8/src/sandbox/trusted-pointer-table.h and indirect-pointer-tag.h. | Default on (with sandbox) | All | Limited |
| Trusted Space | TrustedSpace is a V8 heap region placed outside the sandbox cage; sensitive objects (select Maps, bytecode handlers) live there so in-cage corruption cannot reach them directly. | Default on (with sandbox) | All | Boundary, not bypass target |
| CppHeap Pointer Table | CppHeapPointerTable indirects pointers from V8-heap objects into the Oilpan / cppgc C++ heap, applying the same handle-based protection across the heap boundary. See v8/src/sandbox/cppheap-pointer-table.h. | Default on (with sandbox) | All | Same class |
| JS Dispatch Table | JSDispatchTable indirects every JS function dispatch through a write-protected table indexed by JSDispatchHandle, supporting leaptiering (seamless tier switching) without exposing raw code pointers to sandboxed code. See v8/src/sandbox/js-dispatch-table.h. | Default on | All | Same class |
| Trap-based Wasm bounds | Wasm memory accesses skip explicit bounds-cmp instructions; OOB accesses fault and are caught by kTrapHandler (v8/src/trap-handler/), which converts the signal into a Wasm trap. | Default on | 64-bit | Holds |
| Hardware sandbox (PKU) | V8_ENABLE_SANDBOX_HARDWARE_SUPPORT uses Intel MPK / PKU keys (V8_HAS_PKU_JIT_WRITE_PROTECT) to enforce the sandbox/trusted-region boundary in hardware; M148's CodeSandboxingMode enum (kSandboxed / kUnsandboxed) annotates which code regions run under that enforcement. See v8/src/sandbox/hardware-support.h and code-sandboxing-mode.h. | Experimental | x64 Linux/CrOS | — |
| Mitigation | Details | Enabled? | OS | Bypass |
|---|---|---|---|---|
| MAP_JIT W^X | On Apple Silicon, V8's JIT region is mapped MAP_JIT and toggled per-thread between writable and executable via pthread_jit_write_protect_np; RwxMemoryWriteScope brackets writes, providing per-thread W^X. | Default on | macOS arm64 | Yes |
| Dual-mapping W^X | On Linux and Android, V8's JIT pages are dual-mapped via mmap aliasing — one view writable, one executable — so executable code is never simultaneously writable. See code-space-access.h. | Default on | Linux/Android | Yes |
| Windows JIT W^X | Windows JIT is not W^X-enforced: the renderer uses MITIGATION_DYNAMIC_CODE_DISABLE_WITH_OPT_OUT so V8 can opt out of strict ACG and keep writable+executable JIT pages. | Off | Windows | — |
| CFI-icall in TurboFan/Wasm | Where Clang CFI is on (Linux x64 official), TurboFan- and Wasm-emitted indirect calls get LLVM cfi-icall checks via use_cfi_icall; call sites that can't carry type metadata opt out with V8_CLANG_NO_SANITIZE. | Default on (where CFI on) | Linux x64 official | Yes |
| Short builtin calls | With v8_enable_short_builtin_calls, embedded builtins are laid out close enough to the heap (within kShortBuiltinCallsOldSpaceSizeThreshold) to be reached by direct rather than indirect calls, shrinking the icall surface. | Default on | All | — |
| --jitless | --jitless (FLAG_jitless) runs V8 in interpreter-only mode, disabling TurboFan, Maglev, Sparkplug, and the Wasm baseline JIT — eliminating writable-executable pages and unlocking strict ACG on Windows. | Opt-in | All | — |
| Spectre v1 masking (V8) | Early JIT-level Spectre v1 mitigation (branch load poisoning, --branch-load-poisoning) was retired in favor of Site Isolation; no active masking code remains. | Retired | — | — |
| Mitigation | Details | Enabled? | OS | Bypass |
|---|---|---|---|---|
| Multi-process architecture | Chrome splits responsibilities across renderer, browser, GPU, and utility processes under content/browser and content/renderer; RenderProcessHost and ProcessLauncher manage spawning. | Default on | All | — |
| Site Isolation | Each web site is placed in its own renderer process (--site-per-process, IsolateOrigins); SiteIsolationPolicy (content/browser/site_isolation_policy.cc) enforces strict site-per-process on desktop, partial on low-RAM Android. | Default on (desktop); partial (Android low-RAM) | All | Yes |
| OOPIFs | Out-of-process iframes (OOPIFs) place cross-site iframes in their own renderer process; isolated sandboxed iframes (AreIsolatedSandboxedIframesEnabled) extend this to same-origin sandboxed frames. | Default on | All | Yes |
| Origin-Agent-Cluster (OAC) | A site can opt into per-origin isolation finer than site isolation via the Origin-Agent-Cluster header (kOriginIsolationHeader), reflected in JS as document.originAgentCluster. | Opt-in (by site) | All | — |
| Zygote | On Linux/CrOS/Android, renderers are spawned from a pre-forked, pre-hardened zygote process managed by ZygoteHost; an intermediate kZygoteIntermediateSandbox primes sandbox state before the renderer-specific policy is applied, and the zygote socket carries spawn requests. | Default on | Linux/CrOS/Android | Yes (Zygote socket) |
| seccomp-bpf | On Linux/CrOS/Android, the renderer is constrained by a seccomp-bpf syscall allowlist defined in BaselinePolicy / BaselinePolicyAndroid (sandbox/linux/seccomp-bpf-helpers/); disallowed syscalls return errno or kill the process. | Default on | Linux/CrOS/Android | Yes (via kernel) |
| User namespaces | On Linux/CrOS, the sandbox is built on CLONE_NEWUSER (namespace_sandbox), replacing the older setuid_sandbox helper so no setuid bit is required. | Default on | Linux/CrOS | Yes (via kernel) |
| Landlock | On Linux, the renderer installs a Landlock LSM ruleset (landlock_create_ruleset, linux_landlock.h) restricting filesystem access; enabled since M97. | Default on (M97+) | Linux | Limited |
| AppContainer + restricted token | On Windows, the renderer runs inside an AppContainer (AppContainerBase / AppContainerProfile, sandbox/win/src/app_container_base.cc) at low integrity level with a restricted token, sharply limiting object access. | Default on | Windows | Yes |
| Seatbelt profile | On macOS, the renderer is confined by a Seatbelt .sb profile applied via sandbox_init_with_parameters (sandbox/mac/seatbelt.cc) — the same App Sandbox mechanism Apple uses for sandboxed apps. | Default on | macOS | Yes |
| isolatedProcess / SELinux | On Android, the renderer runs as an isolatedProcess in the isolated_app SELinux domain (seapp_contexts), with Binder and file access denied beyond what's explicitly granted. | Default on | Android | Yes |
| Win32k lockdown | The renderer sets MITIGATION_WIN32K_DISABLE (PROCESS_CREATION_MITIGATION_POLICY_WIN32K_SYSTEM_CALL_DISABLE_ALWAYS_ON) so calls into win32k.sys are blocked, removing a large kernel attack surface. | Default on | Windows | Yes |
| Code Integrity Guard (CIG) | MITIGATION_FORCE_MS_SIGNED_BINS (PROCESS_CREATION_MITIGATION_POLICY_BLOCK_NON_MICROSOFT_BINARIES_ALWAYS_ON, MicrosoftSignedOnly) makes the renderer reject load of any non-Microsoft-signed DLL. | Default on (renderer) | Windows | Limited |
| Arbitrary Code Guard (ACG) | Strict ACG (MITIGATION_DYNAMIC_CODE_DISABLE, PROCESS_CREATION_MITIGATION_POLICY_PROHIBIT_DYNAMIC_CODE_ALWAYS_ON, ProhibitDynamicCode) blocks all dynamic code generation; the renderer instead uses the opt-out variant MITIGATION_DYNAMIC_CODE_DISABLE_WITH_OPT_OUT so V8's JIT can keep running. Strict mode is only viable under --jitless. | Off in renderer; opt-in with --jitless | Windows | — |
| Intel CET shadow stack (process) | Intel CET's user shadow stack (PROCESS_CREATION_MITIGATION_POLICY2_CET_USER_SHADOW_STACKS_ALWAYS_ON) is requested per process; MITIGATION_CET_STRICT_MODE opts a process into hard-fail (opt-in), and MITIGATION_CET_DISABLED opts a process out entirely. | Conditional; strict mode opt-in | Windows ≥20H1 x64 | Yes |
| FSCTL syscall disable | MITIGATION_FSCTL_SYSTEM_CALL_DISABLE blocks FSCTL control codes to NtFsControlFile, narrowing a historically rich kernel attack surface; supported on Windows 10 22H2+. | Default on (where supported) | Windows 10 22H2+ | New |
| Restrict core sharing | MITIGATION_RESTRICT_CORE_SHARING (Windows 11 24H2+) prevents the renderer from sharing an SMT/hyperthread core with another security domain, mitigating same-core side-channel leaks. | Default on (where supported) | Windows 11 24H2+ | New |
| Module tampering protection | MITIGATION_MODULE_TAMPERING_PROTECTION detects in-process IAT (Import Address Table) patching and remaps the affected module from a clean on-disk image, defending against import-table hijacking that would otherwise sidestep CIG. Lands in M149. | Emergent (M149+) — not in M148 stable | Windows | New |
| No-child-process policy | The renderer cannot spawn child processes; all process launches go through ChildProcessLauncher in the browser, enforced at the content layer rather than via a single OS mitigation flag. | Default on | All | Yes (browser-side bugs) |
| Misc Windows process mitigations | The renderer also applies MITIGATION_EXTENSION_POINT_DISABLE (no AppInit DLLs), MITIGATION_NONSYSTEM_FONT_DISABLE (no third-party fonts), and MITIGATION_IMAGE_LOAD_NO_REMOTE / _NO_LOW_LABEL (ProcessImageLoadPolicy) to block remote and low-integrity DLL loads. | Default on (renderer) | Windows | Limited |
| Sandbox broker | A privileged broker process (Windows: BrokerServices / TargetProcess in sandbox/win/src/broker_services.cc; Linux: namespace broker) mediates the small set of OS operations the renderer is allowed to perform — broker bugs are sandbox escapes by definition. | Default on | Windows, Linux | Yes |
| Network Service sandbox | The Network Service (services/network/) runs in its own sandboxed process (kNetwork sandbox type, NetworkProcessSandbox) — fully sandboxed on desktop, partial on mobile. | Default on (desktop); partial (mobile) | All | Yes |
| LPAC | On Windows, the network and audio services run inside a Less-Privileged AppContainer (LowPrivilegeAppContainer, IsLpacEnabled) — a tighter variant than the renderer's AppContainer, with only explicitly granted capabilities (lpacCom, lpacPnpNotifications, etc.). | Partial | Windows | Limited |
| GPU process sandbox | The GPU process runs in the kGpu sandbox (GpuSandbox); sandbox strength is constrained by what the platform driver requires the process to access, leaving a substantial attack surface in the driver itself. | Default on | All | Yes |
| Specialized service sandboxes | Newer per-service sandbox types in sandbox/policy/mojom/sandbox.mojom — kOnDeviceModelExecution, kHardwareVideoDecoding / kHardwareVideoEncoding, kPrintBackend, kScreenAI, kIme, kTts, kMirroring, kOnDeviceTranslation, kShapeDetection — give each subsystem its own narrow policy. | Default on per-feature | Platform-specific | — |
| Utility / Audio isolation | Audio (kAudio) and generic utility (kUtility) services run in their own sandboxed processes rather than in the renderer or browser. | Default on | All | Limited |
| Mitigation | Details | Enabled? | OS | Bypass |
|---|---|---|---|---|
| Interface attribute enforcement | Mojom-level capability gating via [RuntimeFeature], [RequireContext], [AllowedContext], and [MinVersion] attributes — enforced at codegen time by mojom_restrictions_check.py and mojom_interface_feature_check.py — restricts which contexts can bind or send which interfaces. | Default on | All | Yes (mis-scoped bindings) |
| Bind-time caller validation | On BindReceiver, Mojo tracks the source node (set_source_node) and lets endpoints reject unexpected callers; mis-routed messages report via NotifyBadMessageFrom / BadMessageCallback, which can kill the offending process. | Default on (partial) | All | Yes |
| Message ordinal scrambling | When enable_mojom_message_id_scrambling is on (official non-CrOS desktop builds), ScrambleMethodOrdinals in mojo/public/tools/bindings/mojom_bindings_generator.py derives each wire method ID as the first 31 bits of SHA-256(salt + interface + index), with the per-build salt sourced from //chrome/VERSION — raising the bar for cross-pipe confusion and blind probing. | Default on | mac/win/linux (official, non-CrOS) | Limited |
| Fuzzing infrastructure | In-tree Mojo fuzzing: MojoLPM (libFuzzer + LPM-driven protocol fuzzing), proto-based fuzzers, mojo_parse_message_fuzzer, and channel_mac_fuzzer, all gated by enable_mojom_fuzzer. | Default on | All | — |
| MojoJS gating | JavaScript-to-Mojo bindings (MojoBindingsController, MojoJsFeatures) are restricted to the main frame's isolated world for WebUI (kMojoWebUi) and only opt in via EnableMojoJsBindings / AllowMojoJSForProcess — they are not exposed to web content in stable. | Default on (off for web) | All | — |
| Capability-based validation | Mojo validates every incoming message at the receiver — typed enums, struct header / version, pointer overflow, ValidateNonNullableUnion (validation_util.h); a malformed message triggers ReportBadMessage / BadMessageCallback, which terminates the sender. | Default on | All | Yes (validation-logic bugs) |
| IsolatedConnection | mojo::IsolatedConnection opens a point-to-point Mojo channel that is not joined to the global Mojo node graph, used where strict cross-process isolation is wanted. | Default on | All | — |
| Mitigation | Details | Enabled? | OS | Bypass |
|---|---|---|---|---|
| LLVM CFI | Clang's LLVM CFI (is_cfi; -fsanitize=cfi-vcall / -cfi-icall / -cfi-cast via build/config/sanitizers/sanitizers.gni) provides forward-edge type-based call protection — vtable calls and indirect calls are checked against the legal type set — using ThinLTO for cross-DSO coverage. On by default only in official Linux x64 and CrOS device builds; use_cfi_icall and use_cfi_cast are narrower still. | Default on (official builds) | Linux x64, CrOS device | Yes |
| ShadowCallStack (SCS) | ShadowCallStack (-fsanitize=shadow-call-stack, enable_shadow_call_stack) keeps a separate read-only return-address stack on arm64, anchored at the reserved x18 register; opt-in per Android arm64 build. | Default on (opt-in per build) | Android arm64 | Limited |
| Intel CET shadow stack (compile) | Windows x64 official binaries are linked CET-compatible (/CETCOMPAT, enable_cet_shadow_stack), letting the OS enable the hardware shadow stack on supported CPUs. | Default on (official) | Windows x64 | Yes |
| Arm PAC | Arm Pointer Authentication / PAUTH (ARMv8.3-A) signs return addresses (PACIASP) and verifies them on return (AUTIASP); enabled via -mbranch-protection=pac-ret under arm_control_flow_integrity=standard on Linux/Android arm64. | Default on | Linux/Android arm64 | Yes |
| Arm BTI | Arm Branch Target Identification (ARMv8.5-A) requires every indirect-branch landing pad to be a BTI instruction; enabled via -mbranch-protection=standard and link-time -Wl,-z,force-bti / lld_branch_target_hardening on Linux/Android arm64. | Default on | Linux/Android arm64 | Yes |
| Stack canaries | Compiler-inserted stack cookies (SSP, also called GS cookies) via -fstack-protector or -fstack-protector-strong depending on platform/config, validated on function return through __stack_chk_fail. | Default on | All | Yes |
| SafeStack | SafeStack (-fsanitize=safe-stack) split the stack into a safe and an unsafe stack; removed from Chrome's build configuration. | Removed | — | — |
| Mitigation | Details | Enabled? | OS | Bypass |
|---|---|---|---|---|
| ASLR | Address Space Layout Randomization for image, heap, and stack — Windows /DYNAMICBASE, POSIX position-independent code/executable (-fPIC / -fPIE, PIE binaries). | Default on | All | Yes |
| High-entropy ASLR | On 64-bit Windows, /HIGHENTROPYVA opts into the wider 64-bit ASLR entropy range; corresponding POSIX defaults apply on Linux/Android. | Default on | 64-bit | Yes |
| DEP / NX | Data Execution Prevention / NX: Windows /NXCOMPAT and POSIX -Wl,-z,noexecstack mark data pages non-executable so injected data can't be jumped to directly. | Default on | All | Yes |
| /SAFESEH | On Windows x86, /SAFESEH (SafeSEH) requires Structured Exception Handlers to live in a known table, validating the SEH chain at dispatch time. | Default on | Windows x86 | Yes |
| RELRO + BIND_NOW | Full RELRO: -Wl,-z,relro makes the GOT read-only after relocation and -Wl,-z,now forces eager symbol resolution, so the PLT no longer needs to write to the GOT at runtime. On for non-component Linux/Android/Fuchsia builds. | Default on (non-component) | Linux/Android/Fuchsia | — |
| _FORTIFY_SOURCE | glibc's fortified-libc wrappers around string and memory functions (__strcpy_chk and friends) — _FORTIFY_SOURCE=2 by default on Linux/Android, =3 on ChromeOS and sysroot+Clang builds, providing compile- and runtime-time bounds checks where the size is statically known. | =2 default; =3 on CrOS and sysroot+Clang | Linux/Android/CrOS | Yes |
| Auto-init stack variables | -ftrivial-auto-var-init=zero (controlled by init_stack_vars) auto-initializes stack-local variables to zero on entry (-ftrivial-auto-var-init=pattern is the fallback), closing the uninitialized-stack-read bug class; on by default everywhere except non-official Android. | Default on | All except non-official Android | Limited |
| ThinLTO + whole-program-vtables | -flto=thin (ThinLTO) plus -fwhole-program-vtables enables link-time optimization and whole-program devirtualization, prerequisites for cross-DSO CFI; on in CFI builds. | Default on (CFI builds) | Linux x64 official, CrOS | — |
| Relative VTables ABI | -fexperimental-relative-c++-abi-vtables switches to a compact vtable layout using relative offsets instead of absolute pointers, hardening vtable layout on Android arm64 component builds. | Default on | Android arm64 component | — |
| libstdc++ / libc++ assertions | Standard-library assertions — _GLIBCXX_DEBUG=1 / _GLIBCXX_ASSERTIONS=1 for libstdc++, _LIBCPP_HARDENING_MODE for libc++ — catch out-of-range access and iterator misuse; enabled in debug and ASan builds. | Debug + ASan only | All | — |
| MTE (toolchain) | Toolchain-level MTE codegen (-march=armv8.5-a+memtag, __arm_mte intrinsics) is not enabled in M148 at the build level; the runtime MTE support in PartitionAlloc covers what's actually deployed. | Not enabled | — | — |
| -fstack-clash-protection | -fstack-clash-protection would insert stack probes to detect stack/heap clash, but no such flag is set in M148's build configuration. | Not found in M148 | — | — |
| HWASan / ASan | Sanitizer builds only — -fsanitize=address (AddressSanitizer) and -fsanitize=hwaddress (HWASan, a hardware-tagged ASan based on Top-Byte-Ignore on arm64); used in dev and fuzz builds, not shipped. | Debug + fuzz only | All (HWASan: Android arm64) | — |
| Mitigation | Details | Enabled? | OS | Bypass |
|---|---|---|---|---|
| CORB | Cross-Origin Read Blocking (orb_api.h) prevents cross-origin responses with protected MIME types (HTML, XML, JSON) from reaching renderers that should not see them; respects X-Content-Type-Options: nosniff. | Default on (coexists with ORB) | All | Partial |
| ORB | Opaque Response Blocking (services/network/orb/, orb_impl.h) is CORB's successor, blocking cross-origin opaque responses from being delivered to renderers based on a stricter classification. | Default on (rolling) | All | Limited |
| COOP / COEP / CORP | Cross-Origin-Opener-Policy, Cross-Origin-Embedder-Policy, and Cross-Origin-Resource-Policy headers (with values such as require-corp and same-origin-allow-popups) gate window.crossOriginIsolated, which in turn gates SharedArrayBuffer and high-resolution timers. | Opt-in (by site) | All | Yes |
| Document Isolation Policy (DIP) | Document Isolation Policy (content/browser/security/dip/, feature kDocumentIsolationPolicyWithoutSiteIsolation) grants a document crossOriginIsolated without requiring full Site Isolation for the embedding context. | Opt-in (feature) | All | New |
| Fetch Metadata | Chrome attaches Sec-Fetch-Site / -Mode / -Dest / -User / -Storage-Access headers (sec_header_helpers.cc) so servers can reject unexpected requests — CSRF, XSSI, Spectre cross-origin loads — at the edge. | Default on (Chrome sends) | All | — |
| Private Network Access (PNA) | Private Network Access (a.k.a. CORS-RFC1918 / Local Network Access; local_network_access_checker) blocks requests from public origins to private/local IP ranges unless preflighted, mitigating router and intranet attacks. | Default on (rolling) | All | Limited |
| HTTPS-Upgrades + HTTPS-First | Chrome automatically attempts HTTPS first for http:// navigations; HTTPS-First Mode (HTTPS-Only Mode) requires explicit user opt-in to fall back to plaintext (force_no_https_upgrade). | Default on | All | Limited |
| Encrypted Client Hello (ECH) | Encrypted Client Hello encrypts the TLS SNI using a public key fetched from the DNS HTTPS resource record (SVCB family), preventing on-path observers from learning the hostname being connected to. | Default on | All | — |
| HSTS preload | Chrome ships an HTTP Strict Transport Security preload list (transport_security_state, AddHSTS) so listed hosts are HTTPS-only from the first request — no opportunity for SSL stripping on initial connect. | Default on | All | Limited |
| Schemeful Same-Site | Schemeful Same-Site (schemeful_site.h) treats http:// and https:// versions of the same eTLD+1 as cross-site for SameSite cookie purposes, closing a downgrade-attack path. | Default on | All | Limited |
| SameSite=Lax default | Cookies without an explicit SameSite attribute default to Lax (CookieSameSite::LAX_MODE, kSameSiteByDefaultCookies), mitigating cross-site request forgery. | Default on | All | Yes |
| First-Party Sets | First-Party Sets, also called Related Website Sets (FPS / RWS — GlobalFirstPartySets, FirstPartySetsHandlerImpl), let a controlling site declare a set of related domains that share certain storage and identity boundaries. | Default on | All | — |
| DIPS | Bounce Tracking Mitigations (DIPS — btm_bounce_detector, Privacy.DIPS UMA) identify domains used purely as redirect-bounce trackers and clear their state. | Default on | All | — |
| BFCache security | Back-Forward Cache (BackForwardCacheImpl) keeps the prior page's renderer process alive but isolated; pages only enter BFCache when no cross-process leaks are possible. | Default on | All | Limited |
| Trusted Types | Trusted Types (TrustedHTML, TrustedScript, TrustedScriptURL, trusted_types_names.h) require typed wrappers before passing strings to DOM-XSS sinks; opt-in for web content, mandatory for chrome:// WebUI. | Opt-in (mandatory for WebUI) | All | — |
| CSP / XFO / nosniff | Content-Security-Policy (with directives such as script-src and frame-ancestors), X-Frame-Options for legacy framing, and X-Content-Type-Options: nosniff to disable MIME sniffing — all enforced where sites set them. | Default on (where set by site) | All | Yes |
| Permissions Policy | Permissions Policy (formerly Feature Policy, with sibling Document Policy; permissions_policy/) lets a document gate which browser features can be used by itself and by embedded frames. | Default on | All | — |
| Mitigation | Details | Enabled? | OS | Bypass |
|---|---|---|---|---|
| Site Isolation (Spectre) | Site Isolation places different sites in different OS processes (ChildProcessSecurityPolicy enforces the boundary), so a Spectre v1/v2 transient-execution read inside a renderer cannot reach another site's data — that data lives in another address space entirely. | Default on (desktop); partial (Android) | All | Yes |
| SAB COOP+COEP gating | SharedArrayBuffer is only available to documents that have set COOP+COEP headers granting crossOriginIsolated (SharedArrayBufferIssueType tracks violations), since SAB enables the high-resolution timers Spectre PoCs depend on. | Default on | All | Yes |
| performance.now() clamp | ClampTimeResolution (time_clamper.h) quantizes performance.now() to kCoarseResolutionMicroseconds = 100µs without crossOriginIsolated and kFineResolutionMicroseconds = 5µs with it, denying easy high-resolution timing for side-channel attacks. | Default on | All | Yes |
| OS microarch mitigations | Microarchitectural mitigations against branch-target-injection and related transient-execution attacks — retpoline, IBRS / IBPB / eIBRS, STIBP — are configured at the OS/kernel level; Chrome inherits whatever the OS provides. | OS-level (Chrome inherits) | All | Yes |
| Cross-domain SMT restriction | MITIGATION_RESTRICT_CORE_SHARING (Windows 11 24H2+) prevents the renderer's threads from sharing an SMT/hyperthread core with another security domain, mitigating cross-domain hyperthread side-channel leaks. | Default on (where supported) | Windows 11 24H2+ | New |
Not all the mitigations at once are at work against every Chrome exploit chain. An exploit would usually hit a small subset of mitigations, which depends on the bug class, operating system, hardware architecture, field trials configuration, user configuration, Chrome version, specific bug instance shape, and other factors.
That said, certain mitigations are more prohibitive while others are mostly obstacles in the exploit engineering process.