CVE-2018-1019
Description
Microsoft Edge and ChakraCore are vulnerable to remote code execution via a use-after-free of a JavascriptExceptionObject in the Chakra scripting engine.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
Microsoft Edge and ChakraCore are vulnerable to remote code execution via a use-after-free of a JavascriptExceptionObject in the Chakra scripting engine.
Vulnerability
A remote code execution vulnerability exists in the way the Chakra scripting engine handles objects in memory in Microsoft Edge and ChakraCore [1], [3]. The root cause is a use-after-free of a JavascriptExceptionObject during exception handling, specifically within the DoThrow function where a SetPendingFinallyException call is made [2]. This affects all versions of Microsoft Edge on Windows 10 and ChakraCore prior to the fix that introduced the PendingFinallyExceptionStack scoped object [2], [3].
Exploitation
An attacker can trigger this vulnerability by convincing a user to view a specially crafted web page in Microsoft Edge, or by exploiting an application that embeds a vulnerable version of ChakraCore [1]. The attacker needs no special network position beyond serving the malicious page. The exploit leverages the use-after-free by first triggering an exception that leads to a dangling pointer, then performing a sequence of JavaScript operations that reallocate the freed memory to gain control of the engine's execution flow [2].
Impact
Successful exploitation achieves remote code execution in the context of the current user. The attacker can gain the same user rights as the victim, which on Windows 10 for 32-bit and x64-based Systems can lead to full compromise of the affected system [1], [3]. The CIA impact is complete loss of confidentiality, integrity, and availability.
Mitigation
Microsoft released a security update on April 10, 2018 as part of the April 2018 Patch Tuesday, fixing the vulnerability in both Microsoft Edge and ChakraCore [1], [3]. The fix is included in the commit 14a2773 in the ChakraCore repository, which wraps the SetPendingFinallyException call in a scoped PendingFinallyExceptionStack object to prevent use-after-free [2]. Users should apply the latest Windows updates. ChakraCore 1.11 and later include the fix; support for ChakraCore ended March 9, 2021, and users are advised to migrate to maintained alternatives [4].
- NVD - CVE-2018-1019
- [CVE-2018-1019] Use after free of JavascriptExceptionObject - Individual · chakra-core/ChakraCore@14a2773
- Microsoft ChakraCore Scripting Engine CVE-2018-1019 Remote Memory Corruption Vulnerability
- GitHub - chakra-core/ChakraCore: ChakraCore is an open source Javascript engine with a C API.
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.8.3 | 1.8.3 |
Affected products
3- Range: ChakraCore
Patches
114a2773eeefb[CVE-2018-1019] Use after free of JavascriptExceptionObject - Individual
4 files changed · +85 −52
lib/Runtime/Base/ThreadContext.cpp+1 −1 modified@@ -72,6 +72,7 @@ const Js::PropertyRecord * const ThreadContext::builtInPropertyRecords[] = }; ThreadContext::RecyclableData::RecyclableData(Recycler *const recycler) : + pendingFinallyException(nullptr), soErrorObject(nullptr, nullptr, nullptr, true), oomErrorObject(nullptr, nullptr, nullptr, true), terminatedErrorObject(nullptr, nullptr, nullptr), @@ -94,7 +95,6 @@ ThreadContext::ThreadContext(AllocationPolicyManager * allocationPolicyManager, isThreadBound(false), hasThrownPendingException(false), hasBailedOutBitPtr(nullptr), - pendingFinallyException(nullptr), noScriptScope(false), heapEnum(nullptr), threadContextFlags(ThreadContextFlagNoFlag),
lib/Runtime/Base/ThreadContext.h+4 −4 modified@@ -441,8 +441,6 @@ class ThreadContext sealed : private: const Js::PropertyRecord * emptyStringPropertyRecord; - - Js::JavascriptExceptionObject * pendingFinallyException; bool noScriptScope; #ifdef ENABLE_SCRIPT_DEBUGGING @@ -557,6 +555,8 @@ class ThreadContext sealed : Field(Js::TempArenaAllocatorObject *) temporaryArenaAllocators[MaxTemporaryArenaAllocators]; Field(Js::TempGuestArenaAllocatorObject *) temporaryGuestArenaAllocators[MaxTemporaryArenaAllocators]; + Field(Js::JavascriptExceptionObject *) pendingFinallyException; + Field(Js::JavascriptExceptionObject *) exceptionObject; Field(bool) propagateException; @@ -1292,12 +1292,12 @@ class ThreadContext sealed : void SetPendingFinallyException(Js::JavascriptExceptionObject * exceptionObj) { - pendingFinallyException = exceptionObj; + recyclableData->pendingFinallyException = exceptionObj; } Js::JavascriptExceptionObject * GetPendingFinallyException() { - return pendingFinallyException; + return recyclableData->pendingFinallyException; } Js::EntryPointInfo ** RegisterEquivalentTypeCacheEntryPoint(Js::EntryPointInfo * entryPoint);
lib/Runtime/Language/JavascriptExceptionOperators.cpp+70 −47 modified@@ -72,6 +72,17 @@ namespace Js m_threadContext->SetTryCatchFrameAddr(m_prevTryCatchFrameAddr); } + JavascriptExceptionOperators::PendingFinallyExceptionStack::PendingFinallyExceptionStack(ScriptContext* scriptContext, Js::JavascriptExceptionObject *exceptionObj) + { + m_threadContext = scriptContext->GetThreadContext(); + m_threadContext->SetPendingFinallyException(exceptionObj); + } + + JavascriptExceptionOperators::PendingFinallyExceptionStack::~PendingFinallyExceptionStack() + { + m_threadContext->SetPendingFinallyException(nullptr); + } + bool JavascriptExceptionOperators::CrawlStackForWER(Js::ScriptContext& scriptContext) { return Js::Configuration::Global.flags.WERExceptionSupport && !scriptContext.GetThreadContext()->HasCatchHandler(); @@ -199,9 +210,11 @@ namespace Js JavascriptExceptionOperators::DoThrow(exception, scriptContext); } - scriptContext->GetThreadContext()->SetPendingFinallyException(exception); - void *continuation = amd64_CallWithFakeFrame(finallyAddr, frame, spillSize, argsSize, exception); - return continuation; + { + Js::JavascriptExceptionOperators::PendingFinallyExceptionStack pendingFinallyExceptionStack(scriptContext, exception); + void *continuation = amd64_CallWithFakeFrame(finallyAddr, frame, spillSize, argsSize, exception); + return continuation; + } } scriptContext->GetThreadContext()->SetHasBailedOutBitPtr(nullptr); @@ -371,13 +384,15 @@ namespace Js JavascriptExceptionOperators::DoThrow(exception, scriptContext); } - scriptContext->GetThreadContext()->SetPendingFinallyException(exception); + { + Js::JavascriptExceptionOperators::PendingFinallyExceptionStack pendingFinallyExceptionStack(scriptContext, exception); #if defined(_M_ARM) - void * finallyContinuation = arm_CallEhFrame(finallyAddr, framePtr, localsPtr, argsSize); + void * finallyContinuation = arm_CallEhFrame(finallyAddr, framePtr, localsPtr, argsSize); #elif defined(_M_ARM64) - void * finallyContinuation = arm64_CallEhFrame(finallyAddr, framePtr, localsPtr, argsSize); + void * finallyContinuation = arm64_CallEhFrame(finallyAddr, framePtr, localsPtr, argsSize); #endif - return finallyContinuation; + return finallyContinuation; + } } scriptContext->GetThreadContext()->SetHasBailedOutBitPtr(nullptr); @@ -699,60 +714,68 @@ namespace Js JavascriptExceptionOperators::DoThrow(pExceptionObject, scriptContext); } - scriptContext->GetThreadContext()->SetPendingFinallyException(pExceptionObject); + { + Js::JavascriptExceptionOperators::PendingFinallyExceptionStack pendingFinallyExceptionStack(scriptContext, pExceptionObject); - void* newContinuationAddr = NULL; + if (!tryAddr) + { + // Bug in compiler optimizer: dtor is not called, it is a compiler bug + // The compiler thinks the asm cannot throw, so add an explicit throw to generate dtor calls + Js::Throw::InternalError(); + } + void* newContinuationAddr = NULL; #ifdef _M_IX86 - void *savedEsp; + void *savedEsp; - __asm - { - // Save and restore the callee-saved registers around the call. - // TODO: track register kills by region and generate per-region prologs and epilogs - push esi - push edi - push ebx + __asm + { + // Save and restore the callee-saved registers around the call. + // TODO: track register kills by region and generate per-region prologs and epilogs + push esi + push edi + push ebx - // 8-byte align frame to improve floating point perf of our JIT'd code. - // Save ESP - mov ecx, esp - mov savedEsp, ecx - and esp, -8 + // 8-byte align frame to improve floating point perf of our JIT'd code. + // Save ESP + mov ecx, esp + mov savedEsp, ecx + and esp, -8 - // Set up the call target - mov eax, handlerAddr + // Set up the call target + mov eax, handlerAddr #if 0 && defined(_CONTROL_FLOW_GUARD) - // verify that the call target is valid - mov ebx, eax; save call target - mov ecx, eax - call[__guard_check_icall_fptr] - mov eax, ebx; restore call target + // verify that the call target is valid + mov ebx, eax; save call target + mov ecx, eax + call[__guard_check_icall_fptr] + mov eax, ebx; restore call target #endif - // save the current frame ptr, and adjust the frame to access - // locals in native code. - push ebp - mov ebp, framePtr - call eax - pop ebp + // save the current frame ptr, and adjust the frame to access + // locals in native code. + push ebp + mov ebp, framePtr + call eax + pop ebp - // The native code gives us the address where execution should continue on exit - // from the finally, but only if flow leaves the finally before it completes. - mov newContinuationAddr, eax + // The native code gives us the address where execution should continue on exit + // from the finally, but only if flow leaves the finally before it completes. + mov newContinuationAddr, eax - // Restore ESP - mov ecx, savedEsp - mov esp, ecx + // Restore ESP + mov ecx, savedEsp + mov esp, ecx - pop ebx - pop edi - pop esi - } + pop ebx + pop edi + pop esi + } #else - AssertMsg(FALSE, "Unsupported native try-finally handler"); + AssertMsg(FALSE, "Unsupported native try-finally handler"); #endif - return newContinuationAddr; + return newContinuationAddr; + } } scriptContext->GetThreadContext()->SetHasBailedOutBitPtr(nullptr);
lib/Runtime/Language/JavascriptExceptionOperators.h+10 −0 modified@@ -54,6 +54,16 @@ namespace Js ~TryCatchFrameAddrStack(); }; + class PendingFinallyExceptionStack + { + private: + ThreadContext* m_threadContext; + + public: + PendingFinallyExceptionStack(ScriptContext* scriptContext, Js::JavascriptExceptionObject *exceptionObj); + ~PendingFinallyExceptionStack(); + }; + static void __declspec(noreturn) OP_Throw(Var object, ScriptContext* scriptContext); static void __declspec(noreturn) Throw(Var object, ScriptContext* scriptContext); static void __declspec(noreturn) ThrowExceptionObject(Js::JavascriptExceptionObject* exceptionObject, ScriptContext* scriptContext, bool considerPassingToDebugger = false, PVOID returnAddress = NULL, bool resetStack = false);
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
8- github.com/advisories/GHSA-prhh-h793-h32rghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2018-1019ghsaADVISORY
- www.securityfocus.com/bid/103633mitrevdb-entryx_refsource_BID
- www.securitytracker.com/id/1040650mitrevdb-entryx_refsource_SECTRACK
- github.com/chakra-core/ChakraCore/commit/14a2773eeefb39a6c89c0f6a80072f3cc4b06a78ghsaWEB
- portal.msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2018-1019ghsax_refsource_CONFIRMWEB
- web.archive.org/web/20210124154823/http://www.securityfocus.com/bid/103633ghsaWEB
- web.archive.org/web/20211207123630/http://www.securitytracker.com/id/1040650ghsaWEB
News mentions
0No linked articles in our index yet.