CVE-2020-1914
Description
A logic vulnerability when handling the SaveGeneratorLong instruction in Facebook Hermes prior to commit b2021df620824627f5a8c96615edbd1eb7fdddfc allows attackers to potentially read out of bounds or theoretically execute arbitrary code via crafted JavaScript. Note that this is only exploitable if the application using Hermes permits evaluation of untrusted JavaScript. Hence, most React Native applications are not affected.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
Logic vulnerability in Facebook Hermes's SaveGeneratorLong instruction could allow out-of-bounds read or arbitrary code execution via crafted JavaScript.
Hermes is a JavaScript engine optimized for React Native applications [3]. CVE-2020-1914 is a logic vulnerability in the handling of the SaveGeneratorLong instruction, present in versions prior to commit b2021df620824627f5a8c96615edbd1eb7fdddfc [1]. The flaw arises from improper size calculation or bounds checking when saving generator state, leading to a potential out-of-bounds memory access [4].
Exploitation requires the application to evaluate untrusted JavaScript, which is not the case for most React Native apps that only run trusted first-party code [1]. An attacker who can inject and execute crafted JavaScript could trigger the vulnerability by using a generator function with a large number of local variables, causing the SaveGeneratorLong instruction to be emitted instead of the shorter variant [4].
If successfully exploited, the vulnerability could allow an attacker to read out-of-bounds memory, potentially leaking sensitive information. In a worst-case scenario, it might enable arbitrary code execution, though this has not been proven [1].
The issue was fixed in commit b2021df620824627f5a8c96615edbd1eb7fdddfc, which ensures proper sizing of the generator save operation [4]. Users are advised to update to a patched version of Hermes. React Native applications that do not evaluate untrusted JavaScript are not affected [1].
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.
| Package | Affected versions | Patched versions |
|---|---|---|
hermes-enginenpm | < 0.7.2 | 0.7.2 |
Affected products
2- Facebook/Hermesv5Range: commit prior to b2021df620824627f5a8c96615edbd1eb7fdddfc
Patches
1b2021df62082Fix CVE-2020-1914 by using NEXTINST for SaveGeneratorLong
4 files changed · +52 −15
include/hermes/VM/Interpreter.h+8 −0 modified@@ -37,6 +37,14 @@ class Interpreter { Handle<Environment> envHandle, NativeArgs args); + /// Suspend the generator function and yield to the caller. + /// \param resumeIP Is the IP where the generator should resume from when it + /// is resumed. + static void saveGenerator( + Runtime *runtime, + PinnedHermesValue *frameRegs, + const Inst *resumeIP); + /// Slow path for ReifyArguments resReg, lazyReg /// It assumes that he fast path has handled the case when 'lazyReg' is /// already initialized. It creates a new 'arguments' object and populates it
lib/VM/Interpreter.cpp+18 −15 modified@@ -1001,6 +1001,16 @@ CallResult<HermesValue> Interpreter::interpretFunction( #endif // NDEBUG +/// \def DONT_CAPTURE_IP(expr) +/// \param expr A call expression to a function external to the interpreter. The +/// expression should not make any allocations and the IP should be set +/// immediately following this macro. +#define DONT_CAPTURE_IP(expr) \ + do { \ + NoAllocScope noAlloc(runtime); \ + (void)expr; \ + } while (false) + LLVM_DEBUG(dbgs() << "interpretFunction() called\n"); ScopedNativeDepthTracker depthTracker{runtime}; @@ -1798,25 +1808,18 @@ CallResult<HermesValue> Interpreter::interpretFunction( } CASE(SaveGenerator) { - nextIP = IPADD(ip->iSaveGenerator.op1); - goto doSaveGen; + DONT_CAPTURE_IP( + saveGenerator(runtime, frameRegs, IPADD(ip->iSaveGenerator.op1))); + ip = NEXTINST(SaveGenerator); + DISPATCH; } CASE(SaveGeneratorLong) { - nextIP = IPADD(ip->iSaveGeneratorLong.op1); - goto doSaveGen; + DONT_CAPTURE_IP(saveGenerator( + runtime, frameRegs, IPADD(ip->iSaveGeneratorLong.op1))); + ip = NEXTINST(SaveGeneratorLong); + DISPATCH; } - doSaveGen : { - auto *innerFn = vmcast<GeneratorInnerFunction>( - runtime->getCurrentFrame().getCalleeClosure()); - - innerFn->saveStack(runtime); - innerFn->setNextIP(nextIP); - innerFn->setState(GeneratorInnerFunction::State::SuspendedYield); - ip = NEXTINST(SaveGenerator); - DISPATCH; - } - CASE(StartGenerator) { auto *innerFn = vmcast<GeneratorInnerFunction>( runtime->getCurrentFrame().getCalleeClosure());
lib/VM/Interpreter-slowpaths.cpp+11 −0 modified@@ -9,6 +9,7 @@ #include "JSLib/JSLibInternal.h" #include "hermes/VM/Casting.h" #include "hermes/VM/Interpreter.h" +#include "hermes/VM/StackFrame-inline.h" #include "hermes/VM/StringPrimitive.h" #include "Interpreter-internal.h" @@ -18,6 +19,16 @@ using namespace hermes::inst; namespace hermes { namespace vm { +void Interpreter::saveGenerator( + Runtime *runtime, + PinnedHermesValue *frameRegs, + const Inst *resumeIP) { + auto *innerFn = vmcast<GeneratorInnerFunction>(FRAME.getCalleeClosure()); + innerFn->saveStack(runtime); + innerFn->setNextIP(resumeIP); + innerFn->setState(GeneratorInnerFunction::State::SuspendedYield); +} + ExecutionStatus Interpreter::caseDirectEval( Runtime *runtime, PinnedHermesValue *frameRegs,
test/hermes/es6/generator.js+15 −0 modified@@ -354,3 +354,18 @@ print(iterator.next().value); iterator.return(123); // CHECK-NEXT: 1 // CHECK-NEXT: get return + +// Make sure using SaveGeneratorLong works. +function* saveGeneratorLong() { + yield* [1]; + // Waste some registers, to change SaveGenerator to SaveGeneratorLong. + [].push(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0); +} +print(saveGeneratorLong().next().value); +// CHECK-NEXT: 1
Vulnerability mechanics
Root cause
"An incorrect instruction pointer calculation in the `SaveGeneratorLong` instruction handler leads to an invalid jump during generator suspension."
Attack vector
An attacker can trigger this vulnerability by providing crafted JavaScript code that forces the use of the `SaveGeneratorLong` instruction. When the interpreter processes this instruction, the incorrect instruction pointer calculation allows for out-of-bounds memory access or potential arbitrary code execution. This is only exploitable if the application permits the evaluation of untrusted JavaScript [patch_id=18320].
Affected code
The vulnerability exists in the interpreter logic within `lib/VM/Interpreter.cpp` for the `SaveGeneratorLong` instruction. The implementation incorrectly calculated the next instruction pointer, leading to an invalid jump. This logic error is addressed in `[patch_id=18320]`.
What the fix does
The patch refactors the generator saving logic into a dedicated `saveGenerator` function in `lib/VM/Interpreter-slowpaths.cpp` and updates the interpreter to use `NEXTINST` correctly for both `SaveGenerator` and `SaveGeneratorLong` [patch_id=18320]. By centralizing the logic and ensuring the instruction pointer is advanced correctly, the interpreter avoids the incorrect jump that previously caused the vulnerability. This change ensures consistent and safe handling of generator suspension [patch_id=18320].
Preconditions
- inputThe application must permit the evaluation of untrusted JavaScript.
Generated on May 17, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
5- github.com/advisories/GHSA-327c-qx3v-h673ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2020-1914ghsaADVISORY
- github.com/facebook/hermes/commit/b2021df620824627f5a8c96615edbd1eb7fdddfcghsax_refsource_CONFIRMWEB
- github.com/facebook/hermes/issues/373ghsaWEB
- www.facebook.com/security/advisories/cve-2020-1914ghsax_refsource_CONFIRMWEB
News mentions
0No linked articles in our index yet.