VYPR
High severityNVD Advisory· Published Sep 13, 2018· Updated Aug 5, 2024

CVE-2018-8354

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].

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.

PackageAffected versionsPatched versions
Microsoft.ChakraCoreNuGet
< 1.11.11.11.1

Affected products

3

Patches

1
5192cdc08a03

[CVE-2018-8354] Array guards needed for asmjs on x86

https://github.com/chakra-core/ChakraCoreDerek MorrisJul 2, 2018via ghsa
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

News mentions

0

No linked articles in our index yet.