VYPR
Critical severityNVD Advisory· Published Oct 8, 2020· Updated Aug 4, 2024

CVE-2020-1914

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.

PackageAffected versionsPatched versions
hermes-enginenpm
< 0.7.20.7.2

Affected products

2
  • ghsa-coords
    Range: < 0.7.2
  • Facebook/Hermesv5
    Range: commit prior to b2021df620824627f5a8c96615edbd1eb7fdddfc

Patches

1
b2021df62082

Fix CVE-2020-1914 by using NEXTINST for SaveGeneratorLong

https://github.com/facebook/hermesRiley DulinOct 1, 2020via ghsa
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

News mentions

0

No linked articles in our index yet.