VYPR
High severityNVD Advisory· Published Nov 14, 2018· Updated Aug 5, 2024

CVE-2018-8588

CVE-2018-8588

Description

A memory corruption vulnerability in ChakraCore/Microsoft Edge allows remote code execution via crafted web content.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

A memory corruption vulnerability in ChakraCore/Microsoft Edge allows remote code execution via crafted web content.

Vulnerability

A remote code execution vulnerability exists in the way that the Chakra scripting engine handles objects in memory in Microsoft Edge and ChakraCore [1][2]. This is a memory corruption issue classified as a failure to handle exceptional conditions [2]. Affected versions include Microsoft Edge on multiple Windows 10 editions and ChakraCore prior to the fix [2][3]. The vulnerability is distinct from several other Chakra-related CVEs [1].

Exploitation

An attacker can host specially crafted content on a website and convince a user to visit it (typically via social engineering or by compromising a legitimate site) [2][4]. No authentication or special privileges are required; the attacker only needs the user to open the malicious page in an affected version of Microsoft Edge [2][4]. The Chakra engine improperly handles objects in memory while processing the crafted content, leading to exploitable memory corruption [1][2].

Impact

Successful exploitation allows the attacker to execute arbitrary code in the context of the current user [1][2][4]. If the user is running with administrative privileges, the attacker could gain full control of the system, including installing programs, viewing/changing data, or creating new accounts [1][2]. The impact is remote code execution with the same privileges as the logged-on user [2][4].

Mitigation

Microsoft released a security update as part of the November 2018 Patch Tuesday, which addresses this vulnerability [2][4]. Users should apply the latest updates for Microsoft Edge and Windows 10 immediately [2][4]. ChakraCore users should update to the patched version from the commit that fixed the issue [3]. No workaround is available besides applying the vendor-supplied fix [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.31.11.3

Affected products

3

Patches

1
c76da44c27fc

CVE-2018-8588

https://github.com/chakra-core/ChakraCoreRajat DuaOct 24, 2018via ghsa
6 files changed · +37 24
  • lib/Backend/Lower.cpp+17 22 modified
    @@ -3765,13 +3765,11 @@ Lowerer::GenerateProfiledNewScArrayFastPath(IR::Instr *instr, Js::ArrayCallSiteI
             GenerateMemInit(dstOpnd, Js::JavascriptNativeFloatArray::GetOffsetOfWeakFuncRef(), IR::AddrOpnd::New(weakFuncRef, IR::AddrOpndKindDynamicFunctionBodyWeakRef, m_func), instr, isZeroed);
             // Js::JavascriptArray::MissingItem is a Var, so it may be 32-bit or 64 bit.
             uint const offsetStart = sizeof(Js::SparseArraySegmentBase);
    -        uint const missingItemCount = size * sizeof(double) / sizeof(Js::JavascriptArray::MissingItem);
    -        i = i * sizeof(double) / sizeof(Js::JavascriptArray::MissingItem);
    -        for (; i < missingItemCount; i++)
    +        for (; i < size; i++)
             {
                 GenerateMemInit(
    -                headOpnd, offsetStart + i * sizeof(Js::JavascriptArray::MissingItem),
    -                IR::AddrOpnd::New(Js::JavascriptArray::MissingItem, IR::AddrOpndKindConstantAddress, m_func, true),
    +                headOpnd, offsetStart + i * sizeof(double),
    +                GetMissingItemOpndForAssignment(TyFloat64, m_func),
                     instr, isZeroed);
             }
         }
    @@ -3788,7 +3786,7 @@ Lowerer::GenerateProfiledNewScArrayFastPath(IR::Instr *instr, Js::ArrayCallSiteI
             {
                 GenerateMemInit(
                     headOpnd, offsetStart + i * sizeof(Js::Var),
    -                IR::AddrOpnd::New(Js::JavascriptArray::MissingItem, IR::AddrOpndKindConstantAddress, m_func, true),
    +                GetMissingItemOpndForAssignment(TyVar, m_func),
                     instr, isZeroed);
             }
         }
    @@ -4111,12 +4109,11 @@ Lowerer::GenerateProfiledNewScObjArrayFastPath(IR::Instr *instr, Js::ArrayCallSi
     
             // Js::JavascriptArray::MissingItem is a Var, so it may be 32-bit or 64 bit.
             uint const offsetStart = sizeof(Js::SparseArraySegmentBase);
    -        uint const missingItemCount = size * sizeof(double) / sizeof(Js::JavascriptArray::MissingItem);
    -        for (uint i = 0; i < missingItemCount; i++)
    +        for (uint i = 0; i < size; i++)
             {
                 GenerateMemInit(
    -                headOpnd, offsetStart + i * sizeof(Js::JavascriptArray::MissingItem),
    -                IR::AddrOpnd::New(Js::JavascriptArray::MissingItem, IR::AddrOpndKindConstantAddress, m_func, true),
    +                headOpnd, offsetStart + i * sizeof(double),
    +                GetMissingItemOpndForAssignment(TyFloat64, m_func),
                     instr, isZeroed);
             }
         }
    @@ -4126,9 +4123,9 @@ Lowerer::GenerateProfiledNewScObjArrayFastPath(IR::Instr *instr, Js::ArrayCallSi
             headOpnd = GenerateArrayObjectsAlloc<Js::JavascriptArray>(instr, &size, arrayInfo, &isZeroed, isNoArgs);
             for (uint i = 0; i < size; i++)
             {
    -            GenerateMemInit(
    +             GenerateMemInit(
                     headOpnd, offsetStart + i * sizeof(Js::Var),
    -                IR::AddrOpnd::New(Js::JavascriptArray::MissingItem, IR::AddrOpndKindConstantAddress, m_func, true),
    +                GetMissingItemOpndForAssignment(TyVar, m_func),
                     instr, isZeroed);
             }
         }
    @@ -4159,8 +4156,8 @@ Lowerer::GenerateProfiledNewScObjArrayFastPath(IR::Instr *instr, Js::ArrayCallSi
         uint allocationBucketsCount = ArrayType::AllocationBucketsCount;
         uint(*allocationBuckets)[Js::JavascriptArray::AllocationBucketsInfoSize];
         allocationBuckets = ArrayType::allocationBuckets;
    -    uint sizeFactor = 1;
    -    IRType missingItemType = (arrayInfo && arrayInfo->IsNativeIntArray()) ? IRType::TyInt32 : IRType::TyVar;
    +    
    +    IRType missingItemType = (arrayInfo ? arrayInfo->IsNativeIntArray() ? IRType::TyInt32 : arrayInfo->IsNativeFloatArray() ? IRType::TyFloat64 : IRType::TyVar : IRType::TyVar);
         IR::LabelInstr * arrayInitDone = IR::LabelInstr::New(Js::OpCode::Label, func);
     
         bool isNativeArray = arrayInfo && (arrayInfo->IsNativeIntArray() || arrayInfo->IsNativeFloatArray());
    @@ -4172,9 +4169,7 @@ Lowerer::GenerateProfiledNewScObjArrayFastPath(IR::Instr *instr, Js::ArrayCallSi
         }
         else if (arrayInfo && arrayInfo->IsNativeFloatArray())
         {
    -        // Js::JavascriptArray::MissingItem is a Var, so it may be 32-bit or 64 bit.
    -        sizeFactor = sizeof(double) / sizeof(Js::JavascriptArray::MissingItem);
    -        sizeOfElement = sizeof(Js::JavascriptArray::MissingItem);
    +        sizeOfElement = sizeof(double);
             GenerateArrayInfoIsNativeFloatAndNotIntArrayTest(instr, arrayInfo, arrayInfoAddr, helperLabel);
         }
         else
    @@ -4204,7 +4199,7 @@ Lowerer::GenerateProfiledNewScObjArrayFastPath(IR::Instr *instr, Js::ArrayCallSi
     
         for (uint8 i = 0;i < allocationBucketsCount;i++)
         {
    -        missingItemCount = allocationBuckets[i][Js::JavascriptArray::MissingElementsCountIndex] * sizeFactor;
    +        missingItemCount = allocationBuckets[i][Js::JavascriptArray::MissingElementsCountIndex];
     
             if (i > 0)
             {
    @@ -4235,7 +4230,7 @@ Lowerer::GenerateProfiledNewScObjArrayFastPath(IR::Instr *instr, Js::ArrayCallSi
         // Ensure no. of missingItems written are same
         Assert(missingItemIndex == missingItemInitializedSoFar);
         // Ensure no. of missingItems match what present in allocationBuckets
    -    Assert(missingItemIndex == allocationBuckets[allocationBucketsCount - 1][Js::JavascriptArray::MissingElementsCountIndex] * sizeFactor);
    +    Assert(missingItemIndex == allocationBuckets[allocationBucketsCount - 1][Js::JavascriptArray::MissingElementsCountIndex]);
     
         instr->InsertBefore(arrayInitDone);
     
    @@ -4363,11 +4358,11 @@ Lowerer::GenerateProfiledNewScFloatArrayFastPath(IR::Instr *instr, Js::ArrayCall
     
         // Js::JavascriptArray::MissingItem is a Var, so it may be 32-bit or 64 bit.
         uint const offsetStart = sizeof(Js::SparseArraySegmentBase) + doubles->count * sizeof(double);
    -    uint const missingItem = (size - doubles->count) * sizeof(double) / sizeof(Js::JavascriptArray::MissingItem);
    +    uint const missingItem = (size - doubles->count);
         for (uint i = 0; i < missingItem; i++)
         {
    -        GenerateMemInit(headOpnd, offsetStart + i * sizeof(Js::JavascriptArray::MissingItem),
    -            IR::AddrOpnd::New(Js::JavascriptArray::MissingItem, IR::AddrOpndKindConstantAddress, m_func, true), instr, isHeadSegmentZeroed);
    +        GenerateMemInit(headOpnd, offsetStart + i * sizeof(double),
    +            GetMissingItemOpndForAssignment(TyFloat64, m_func), instr, isHeadSegmentZeroed);
         }
         // Skip pass the helper call
         IR::LabelInstr * doneLabel = IR::LabelInstr::New(Js::OpCode::Label, func);
    
  • lib/Runtime/Library/JavascriptArray.cpp+4 2 modified
    @@ -28,7 +28,7 @@ using namespace Js;
             { 8, 0, 0 },    // allocate space for 8 elements for array of length 6,7,8
         };
     
    -    const Var JavascriptArray::MissingItem = (Var)FloatMissingItemPattern;
    +    const Var JavascriptArray::MissingItem = (Var)VarMissingItemPattern;
     
     #if defined(TARGET_64)
         const Var JavascriptArray::IntMissingItemVar = (Var)(((uint64)IntMissingItemPattern << 32) | (uint32)IntMissingItemPattern);
    @@ -2048,6 +2048,8 @@ using namespace Js;
                         {
                             ((SparseArraySegment<Var>*)seg)->elements[i] = JavascriptNumber::ToVar(ival, scriptContext);
                         }
    +                    SparseArraySegment<Var>* newSeg = (SparseArraySegment<Var>*)seg;
    +                    newSeg->FillSegmentBuffer(seg->length, seg->size);
                     }
                     prevSeg = seg;
                 }
    @@ -2243,7 +2245,7 @@ using namespace Js;
                         }
                     }
                 }
    -            if (seg == newSeg && shrinkFactor != 1)
    +            if (seg == newSeg)
                 {
                     // Fill the remaining slots.
                     newSeg->FillSegmentBuffer(i, seg->size);
    
  • lib/Runtime/Library/JavascriptArray.inl+6 0 modified
    @@ -486,6 +486,8 @@ namespace Js
         template<typename T>
         inline void JavascriptArray::DirectSetItemInLastUsedSegmentAt(const uint32 offset, const T newValue)
         {
    +        Assert(!SparseArraySegment<T>::IsMissingItem(&newValue));
    +
             SparseArraySegment<T> *const seg = (SparseArraySegment<T>*)GetLastUsedSegment();
             Assert(seg);
             Assert(offset < seg->size);
    @@ -526,6 +528,8 @@ namespace Js
             const T newValue,
             StElemInfo *const stElemInfo)
         {
    +        Assert(!SparseArraySegment<T>::IsMissingItem(&newValue));
    +
             SparseArraySegment<T> *const seg = SparseArraySegment<T>::From(head);
             Assert(seg);
             Assert(offset < seg->size);
    @@ -1219,6 +1223,8 @@ SECOND_PASS:
         template<typename T>
         void JavascriptArray::DirectSetItem_Full(uint32 itemIndex, T newValue)
         {
    +        Assert(!SparseArraySegment<T>::IsMissingItem(&newValue));
    +
             DebugOnly(VerifyNotNeedMarshal(newValue));
             this->EnsureHead<T>();
             AnalysisAssert(head);
    
  • lib/Runtime/Library/SparseArraySegment.h+1 0 modified
    @@ -147,6 +147,7 @@ namespace Js
             return JavascriptArray::MissingItem;
         }
         template<> Var SparseArraySegment<int32>::GetMissingItemVar();
    +    Var SparseArraySegment<double>::GetMissingItemVar();
     
         template<>
         inline bool SparseArraySegment<double>::IsMissingItem(const double* value)
    
  • lib/Runtime/Library/SparseArraySegment.inl+6 0 modified
    @@ -229,6 +229,12 @@ namespace Js
             return JavascriptArray::IntMissingItemVar;
         }
     
    +    template<>
    +    inline Var SparseArraySegment<double>::GetMissingItemVar()
    +    {
    +        return (Var)FloatMissingItemPattern;
    +    }
    +
         template<typename T>
         void SparseArraySegment<T>::FillSegmentBuffer(uint32 start, uint32 size)
         {
    
  • lib/Runtime/RuntimeCommon.h+3 0 modified
    @@ -179,6 +179,9 @@ namespace Js
     
     #if FLOATVAR
         const uint64 FloatTag_Value       = 0xFFFCull << 48;
    +    const uint64 VarMissingItemPattern = 0x00040002FFF80002; // Float-tagged representation of FloatMissingItemPattern
    +#else
    +    const int32 VarMissingItemPattern = 0xFFF80002;
     #endif
         const uint64 FloatMissingItemPattern = 0xFFF80002FFF80002;
         const int32 IntMissingItemPattern = 0xFFF80002;
    

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.