CVE-2018-8354
Description
Remote code execution vulnerability in Microsoft Edge and ChakraCore scripting engine due to improper handling of objects in memory, specifically in asm.js mode on x86.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
Remote code execution vulnerability in Microsoft Edge and ChakraCore scripting engine due to improper handling of objects in memory, specifically in asm.js mode on x86.
Vulnerability
A remote code execution vulnerability exists in the way the ChakraCore scripting engine handles objects in memory in Microsoft Edge, affecting both Edge and standalone ChakraCore. This CVE is specific to asm.js mode on x86 platforms, where improper array bounds checking allows memory corruption [1][2][4].
Exploitation
An attacker can craft a malicious web page containing specially crafted asm.js content and persuade a user to visit it (e.g., via a link). No special privileges or user interaction beyond normal browsing is required. The vulnerability is triggered when Edge or ChakraCore processes the malformed asm.js code, leading to memory corruption [3].
Impact
Successful exploitation grants the attacker the ability to execute arbitrary code in the context of the current user. This could lead to full system compromise, including data theft, installation of malware, or further privilege escalation [2][3].
Mitigation
Microsoft released a security update on September 11, 2018 (Patch Tuesday) that addresses this vulnerability. Users should apply the update for Microsoft Edge and ChakraCore. No workaround is available; updating is the only mitigation [2][3][4].
- NVD - CVE-2018-8354
- Microsoft ChakraCore Scripting Engine CVE-2018-8354 Remote Memory Corruption Vulnerability
- Microsoft Edge Multiple Bugs Let Remote Users Execute Arbitrary Code, Obtain Potentially Sensitive Information, Gain Elevated Privileges, and Spoof Content on the Target System
- [CVE-2018-8354] Array guards needed for asmjs on x86 · chakra-core/ChakraCore@5192cdc
AI Insight generated on May 22, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
Microsoft.ChakraCoreNuGet | < 1.11.1 | 1.11.1 |
Affected products
3- Range: ChakraCore
Patches
15192cdc08a03[CVE-2018-8354] Array guards needed for asmjs on x86
1 file changed · +61 −4
lib/Backend/Lower.cpp+61 −4 modified@@ -9274,6 +9274,61 @@ void Lowerer::LowerLdLen(IR::Instr *const instr, const bool isHelper) LowerLdFld(instr, IR::HelperOp_GetProperty, IR::HelperOp_GetProperty, false, nullptr, isHelper); } +IR::Instr* InsertMaskableMove(bool isStore, bool generateWriteBarrier, IR::Opnd* dst, IR::Opnd* src1, IR::Opnd* src2, IR::Opnd* indexOpnd, IR::Instr* insertBeforeInstr, Lowerer* lowerer) +{ + Assert(insertBeforeInstr->m_func->GetJITFunctionBody()->IsAsmJsMode()); + + // Mask with the bounds check operand to avoid speculation issues + const bool usesFastArray = insertBeforeInstr->m_func->GetJITFunctionBody()->UsesWAsmJsFastVirtualBuffer(); + IR::RegOpnd* mask = nullptr; + bool shouldMaskResult = false; + if (!usesFastArray) + { + bool shouldMask = isStore ? CONFIG_FLAG_RELEASE(PoisonTypedArrayStore) : CONFIG_FLAG_RELEASE(PoisonTypedArrayLoad); + if (shouldMask && indexOpnd != nullptr) + { + // indices in asmjs fit in 32 bits, but we need a mask + IR::RegOpnd* temp = IR::RegOpnd::New(indexOpnd->GetType(), insertBeforeInstr->m_func); + lowerer->InsertMove(temp, indexOpnd, insertBeforeInstr, false); + lowerer->InsertAdd(false, temp, temp, IR::IntConstOpnd::New((uint32)src1->GetSize() - 1, temp->GetType(), insertBeforeInstr->m_func, true), insertBeforeInstr); + + // For native ints and vars, we do the masking after the load; we don't do this for + // floats and doubles because the conversion to and from fp regs is slow. + shouldMaskResult = (!isStore) && IRType_IsNativeIntOrVar(src1->GetType()) && TySize[dst->GetType()] <= TySize[TyMachReg]; + + // When we do post-load masking, we AND the mask with dst, so they need to have the + // same type, as otherwise we'll hit asserts later on. When we do pre-load masking, + // we AND the mask with the index component of the indir opnd for the move from the + // array, so we need to align with that type instead. + mask = IR::RegOpnd::New((shouldMaskResult ? dst : indexOpnd)->GetType(), insertBeforeInstr->m_func); + + if (temp->GetSize() != mask->GetSize()) + { + Assert(mask->GetSize() == MachPtr); + Assert(src2->GetType() == TyUint32); + temp = temp->UseWithNewType(TyMachPtr, insertBeforeInstr->m_func)->AsRegOpnd(); + src2 = src2->UseWithNewType(TyMachPtr, insertBeforeInstr->m_func)->AsRegOpnd(); + } + + lowerer->InsertSub(false, mask, temp, src2, insertBeforeInstr); + lowerer->InsertShift(Js::OpCode::Shr_A, false, mask, mask, IR::IntConstOpnd::New(TySize[mask->GetType()] * 8 - 1, TyInt8, insertBeforeInstr->m_func), insertBeforeInstr); + + // If we're not masking the result, we're masking the index + if (!shouldMaskResult) + { + lowerer->InsertAnd(indexOpnd, indexOpnd, mask, insertBeforeInstr); + } + } + } + IR::Instr* ret = lowerer->InsertMove(dst, src1, insertBeforeInstr, generateWriteBarrier); + if(!usesFastArray && shouldMaskResult) + { + // Mask the result if we didn't use the mask earlier to mask the index + lowerer->InsertAnd(dst, dst, mask, insertBeforeInstr); + } + return ret; +} + IR::Instr * Lowerer::LowerLdArrViewElem(IR::Instr * instr) { @@ -9342,7 +9397,8 @@ Lowerer::LowerLdArrViewElem(IR::Instr * instr) } done = instr; } - InsertMove(dst, src1, done); + + InsertMaskableMove(false, true, dst, src1, src2, indexOpnd, done, this); instr->Remove(); return instrPrev; @@ -9390,7 +9446,8 @@ Lowerer::LowerLdArrViewElemWasm(IR::Instr * instr) Assert(!dst->IsFloat64() || src1->IsFloat64()); IR::Instr * done = LowerWasmArrayBoundsCheck(instr, src1); - IR::Instr* newMove = InsertMove(dst, src1, done); + + IR::Instr* newMove = InsertMaskableMove(false, true, dst, src1, instr->GetSrc2(), src1->AsIndirOpnd()->GetIndexOpnd(), done, this); if (m_func->GetJITFunctionBody()->UsesWAsmJsFastVirtualBuffer()) { @@ -9667,8 +9724,8 @@ Lowerer::LowerStArrViewElem(IR::Instr * instr) instr->FreeSrc2(); } } - // wasm memory buffer is not recycler allocated, so we shouldn't generate write barrier - InsertMove(dst, src1, done, false); + // wasm memory buffer is not recycler allocated, so we shouldn't generate write barrier + InsertMaskableMove(true, false, dst, src1, src2, indexOpnd, done, this); instr->Remove(); return instrPrev;
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
9- github.com/advisories/GHSA-6g23-fww6-rfrjghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2018-8354ghsaADVISORY
- www.securityfocus.com/bid/105232mitrevdb-entryx_refsource_BID
- www.securitytracker.com/id/1041623mitrevdb-entryx_refsource_SECTRACK
- github.com/chakra-core/ChakraCore/commit/5192cdc08a030a580ba15d1d9aa50f81a6d92211ghsaWEB
- github.com/chakra-core/ChakraCore/pull/5688ghsaWEB
- portal.msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2018-8354ghsax_refsource_CONFIRMWEB
- web.archive.org/web/20210124202704/http://www.securityfocus.com/bid/105232ghsaWEB
- web.archive.org/web/20210517133345/http://www.securitytracker.com/id/1041623ghsaWEB
News mentions
0No linked articles in our index yet.