VYPR
High severityNVD Advisory· Published Apr 15, 2020· Updated Aug 4, 2024

CVE-2020-0969

CVE-2020-0969

Description

A remote code execution vulnerability exists in the way that the Chakra scripting engine handles objects in memory in Microsoft Edge (HTML-based), aka 'Chakra Scripting Engine Memory Corruption Vulnerability'.

AI Insight

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

A memory corruption vulnerability in the Chakra scripting engine allows remote code execution via Microsoft Edge (HTML-based).

Vulnerability

CVE-2020-0969 is a remote code execution vulnerability in the way the Chakra scripting engine handles objects in memory in Microsoft Edge (HTML-based) [1][2]. The issue is a memory corruption bug that arises during bytecode generation, specifically in the EmitLoadInstance function where the handling of with statements and scope objects was flawed [4]. The root cause is a missing check or improper handling of object types when loading environment objects and unwrapping with scopes, leading to potential use-after-free or corruption [1].

Exploitation

The vulnerability can be triggered remotely by convincing a user to view a specially crafted web page or document that leverages the Chakra engine. No authentication is required, and the attack surface is through the browser, with the user visiting a malicious site or opening a crafted file [2]. The exploit involves manipulating the JavaScript engine's internal state through carefully constructed with statements or similar constructs to corrupt memory [4].

Impact

Successful exploitation could allow an attacker to execute arbitrary code in the context of the current user. If the user has administrative privileges, the attacker could gain full control of the system, install programs, view, change, or delete data, or create new accounts [2]. The vulnerability is rated as 'Critical' in severity [2].

Mitigation

Microsoft released a security update as part of the April 2020 Patch Tuesday, and the fix is included in ChakraCore pull request #6420 [1][2]. The patch modifies the bytecode generator to correctly handle with scopes and ensure proper register usage and object type assertions [4]. Users should apply the update to Microsoft Edge (HTML-based) or update their ChakraCore library to the patched version. ChakraCore 1.11 continued to receive security updates until March 2021, but master branch fixes were merged for the community [3].

AI Insight generated on May 21, 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.181.11.18

Affected products

23
  • ghsa-coords
    Range: < 1.11.18
  • Microsoft/ChakraCorev5
    Range: unspecified
  • Microsoft/Microsoft Edge (EdgeHTML-based) on Windows 10 for 32-bit Systemsv5
    Range: unspecified
  • Microsoft/Microsoft Edge (EdgeHTML-based) on Windows 10 for x64-based Systemsv5
    Range: unspecified
  • Microsoft/Microsoft Edge (EdgeHTML-based) on Windows 10 Version 1607 for 32-bit Systemsv5
    Range: unspecified
  • Microsoft/Microsoft Edge (EdgeHTML-based) on Windows 10 Version 1607 for x64-based Systemsv5
    Range: unspecified
  • Microsoft/Microsoft Edge (EdgeHTML-based) on Windows 10 Version 1709 for 32-bit Systemsv5
    Range: unspecified
  • Microsoft/Microsoft Edge (EdgeHTML-based) on Windows 10 Version 1709 for ARM64-based Systemsv5
    Range: unspecified
  • Microsoft/Microsoft Edge (EdgeHTML-based) on Windows 10 Version 1709 for x64-based Systemsv5
    Range: unspecified
  • Microsoft/Microsoft Edge (EdgeHTML-based) on Windows 10 Version 1803 for 32-bit Systemsv5
    Range: unspecified
  • Microsoft/Microsoft Edge (EdgeHTML-based) on Windows 10 Version 1803 for ARM64-based Systemsv5
    Range: unspecified
  • Microsoft/Microsoft Edge (EdgeHTML-based) on Windows 10 Version 1803 for x64-based Systemsv5
    Range: unspecified
  • Microsoft/Microsoft Edge (EdgeHTML-based) on Windows 10 Version 1809 for 32-bit Systemsv5
    Range: unspecified
  • Microsoft/Microsoft Edge (EdgeHTML-based) on Windows 10 Version 1809 for ARM64-based Systemsv5
    Range: unspecified
  • Microsoft/Microsoft Edge (EdgeHTML-based) on Windows 10 Version 1809 for x64-based Systemsv5
    Range: unspecified
  • Microsoft/Microsoft Edge (EdgeHTML-based) on Windows 10 Version 1903 for 32-bit Systemsv5
    Range: unspecified
  • Microsoft/Microsoft Edge (EdgeHTML-based) on Windows 10 Version 1903 for ARM64-based Systemsv5
    Range: unspecified
  • Microsoft/Microsoft Edge (EdgeHTML-based) on Windows 10 Version 1903 for x64-based Systemsv5
    Range: unspecified
  • Microsoft/Microsoft Edge (EdgeHTML-based) on Windows 10 Version 1909 for 32-bit Systemsv5
    Range: unspecified
  • Microsoft/Microsoft Edge (EdgeHTML-based) on Windows 10 Version 1909 for ARM64-based Systemsv5
    Range: unspecified
  • Microsoft/Microsoft Edge (EdgeHTML-based) on Windows 10 Version 1909 for x64-based Systemsv5
    Range: unspecified
  • Microsoft/Microsoft Edge (EdgeHTML-based) on Windows Server 2016v5
    Range: unspecified
  • Microsoft/Microsoft Edge (EdgeHTML-based) on Windows Server 2019v5
    Range: unspecified

Patches

1
cd58e8e6799a

[CVE-2020-0969]

https://github.com/chakra-core/ChakraCorePaul LeathersMar 11, 2020via ghsa
6 files changed · +53 18
  • lib/Runtime/ByteCode/ByteCodeEmitter.cpp+37 15 modified
    @@ -4262,21 +4262,33 @@ void ByteCodeGenerator::EmitLoadInstance(Symbol *sym, IdentPtr pid, Js::RegSlot
                     funcInfo->FindOrAddReferencedPropertyId(propertyId),
                     envIndex + Js::FrameDisplay::GetOffsetOfScopes() / sizeof(Js::Var));
     
    -            Js::RegSlot tmpReg = funcInfo->AcquireTmpRegister();
    -
                 AssertOrFailFast(scope->GetIsObject());
    -            this->m_writer.SlotI1(Js::OpCode::LdEnvObj, tmpReg,
    -                envIndex + Js::FrameDisplay::GetOffsetOfScopes() / sizeof(Js::Var));
    -
    -            Js::OpCode op = unwrapWithObj ? Js::OpCode::UnwrapWithObj : Js::OpCode::Ld_A;
     
    -            this->m_writer.Reg2(op, instLocation, tmpReg);
    -            if (thisLocation != Js::Constants::NoRegister)
    +            if (unwrapWithObj)
                 {
    -                this->m_writer.Reg2(op, thisLocation, tmpReg);
    +                Js::RegSlot tmpReg = funcInfo->AcquireTmpRegister();
    +
    +                this->m_writer.SlotI1(Js::OpCode::LdEnvObj, tmpReg,
    +                    envIndex + Js::FrameDisplay::GetOffsetOfScopes() / sizeof(Js::Var));
    +
    +                this->m_writer.Reg2(Js::OpCode::UnwrapWithObj, instLocation, tmpReg);
    +                if (thisLocation != Js::Constants::NoRegister)
    +                {
    +                    this->m_writer.Reg2(Js::OpCode::UnwrapWithObj, thisLocation, tmpReg);
    +                }
    +
    +                funcInfo->ReleaseTmpRegister(tmpReg);
                 }
    +            else
    +            {
    +                this->m_writer.SlotI1(Js::OpCode::LdEnvObj, instLocation,
    +                    envIndex + Js::FrameDisplay::GetOffsetOfScopes() / sizeof(Js::Var));
     
    -            funcInfo->ReleaseTmpRegister(tmpReg);
    +                if (thisLocation != Js::Constants::NoRegister)
    +                {
    +                    this->m_writer.Reg2(Js::OpCode::Ld_A, thisLocation, funcInfo->undefinedConstantRegister);
    +                }
    +            }
             }
             else if (scopeLocation != Js::Constants::NoRegister && scopeLocation == funcInfo->frameObjRegister)
             {
    @@ -4288,19 +4300,29 @@ void ByteCodeGenerator::EmitLoadInstance(Symbol *sym, IdentPtr pid, Js::RegSlot
                 this->m_writer.Reg1(Js::OpCode::LdLocalObj, instLocation);
                 if (thisLocation != Js::Constants::NoRegister)
                 {
    -                this->m_writer.Reg1(Js::OpCode::LdLocalObj, thisLocation);
    +                this->m_writer.Reg2(Js::OpCode::Ld_A, thisLocation, funcInfo->undefinedConstantRegister);
                 }
             }
             else
             {
                 this->m_writer.BrProperty(Js::OpCode::BrOnNoProperty, nextLabel, scopeLocation,
                     funcInfo->FindOrAddReferencedPropertyId(propertyId));
     
    -            Js::OpCode op = unwrapWithObj ? Js::OpCode::UnwrapWithObj : Js::OpCode::Ld_A;
    -            this->m_writer.Reg2(op, instLocation, scopeLocation);
    -            if (thisLocation != Js::Constants::NoRegister)
    +            if (unwrapWithObj)
                 {
    -                this->m_writer.Reg2(op, thisLocation, scopeLocation);
    +                this->m_writer.Reg2(Js::OpCode::UnwrapWithObj, instLocation, scopeLocation);
    +                if (thisLocation != Js::Constants::NoRegister)
    +                {
    +                    this->m_writer.Reg2(Js::OpCode::UnwrapWithObj, thisLocation, scopeLocation);
    +                }
    +            }
    +            else
    +            {
    +                this->m_writer.Reg2(Js::OpCode::Ld_A, instLocation, scopeLocation);
    +                if (thisLocation != Js::Constants::NoRegister)
    +                {
    +                    this->m_writer.Reg2(Js::OpCode::Ld_A, thisLocation, funcInfo->undefinedConstantRegister);
    +                }
                 }
             }
     
    
  • lib/Runtime/Language/JavascriptOperators.cpp+1 2 modified
    @@ -2072,8 +2072,7 @@ using namespace Js;
                     // HasProperty will call UnscopablesWrapperObject's HasProperty which will do the filtering
                     // All we have to do here is unwrap the object hence the api call
     
    -                *thisVar = obj->GetThisObjectOrUnWrap();
    -                return *thisVar;
    +                return obj->GetThisAndUnwrappedInstance(thisVar);
                 }
             }
     
    
  • lib/Runtime/Types/RecyclableObject.cpp+6 0 modified
    @@ -331,6 +331,12 @@ namespace Js
             return this;
         }
     
    +    RecyclableObject* RecyclableObject::GetThisAndUnwrappedInstance(Var* thisVar) const
    +    {
    +        *thisVar = this->GetLibrary()->GetUndefined();
    +        return (RecyclableObject*)this;
    +    }
    +
         // In order to avoid a branch, every object has an entry point if it gets called like a
         // function - however, if it can't be called like a function, it's set to DefaultEntryPoint
         // which will emit an error.
    
  • lib/Runtime/Types/RecyclableObject.h+1 0 modified
    @@ -353,6 +353,7 @@ namespace Js {
             virtual uint GetSpecialPropertyCount() const { return 0; }
             virtual PropertyId const * GetSpecialPropertyIds() const { return nullptr; }
             virtual RecyclableObject* GetThisObjectOrUnWrap(); // Due to the withScope object there are times we need to unwrap
    +        virtual RecyclableObject* GetThisAndUnwrappedInstance(Var* thisVar) const;
     
             virtual BOOL HasInstance(Var instance, ScriptContext* scriptContext, IsInstInlineCache* inlineCache = NULL);
     
    
  • lib/Runtime/Types/UnscopablesWrapperObject.cpp+6 0 modified
    @@ -23,6 +23,12 @@ namespace Js
             return static_cast<UnscopablesWrapperObject*>(aValue);
         }
     
    +    RecyclableObject * UnscopablesWrapperObject::GetThisAndUnwrappedInstance(Var* thisVar) const
    +    {
    +        *thisVar = this->GetWrappedObject();
    +        return this->GetWrappedObject();
    +    }
    +
         PropertyQueryFlags UnscopablesWrapperObject::HasPropertyQuery(PropertyId propertyId, _Inout_opt_ PropertyValueInfo* info)
         {
             return JavascriptConversion::BooleanToPropertyQueryFlags(JavascriptOperators::HasPropertyUnscopables(wrappedObject, propertyId));
    
  • lib/Runtime/Types/UnscopablesWrapperObject.h+2 1 modified
    @@ -28,7 +28,8 @@ namespace Js
                 static bool Is(Var aValue);
                 static UnscopablesWrapperObject* FromVar(Var value);
                 static UnscopablesWrapperObject* UnsafeFromVar(Var value);
    -            RecyclableObject *GetWrappedObject() { return wrappedObject; }
    +            RecyclableObject *GetWrappedObject() const { return wrappedObject; }
    +            virtual RecyclableObject* GetThisAndUnwrappedInstance(Var* thisVar) const override;
                 virtual PropertyQueryFlags HasPropertyQuery(PropertyId propertyId, _Inout_opt_ PropertyValueInfo* info) override;
                 virtual BOOL HasOwnProperty(PropertyId propertyId) override;
                 virtual BOOL SetProperty(PropertyId propertyId, Var value, PropertyOperationFlags flags, PropertyValueInfo* info) override;
    

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

5

News mentions

0

No linked articles in our index yet.