Skip to content

FATAL ERROR: v8::ToLocalChecked Empty MaybeLocal #56531

Description

@vdata1

Version

v23.6.0

Platform

Linux SMP Debian 5.10.103-1 (2022-03-07) x86_64 x86_64 x86_64 GNU/Linux

Subsystem

No response

What steps will reproduce the bug?

Hi,

I would like to report a bug, it can be reproduced by running the PoC below:

const {exec} = require('child_process');

Object.defineProperty(Array.prototype, "2", {
  set: function () {},
});

(async function () {
  exec('pwd', (err, stdout, stderr) => {
    console.log(stdout);
  });
})();

Regards,

AH

How often does it reproduce? Is there a required condition?

It reproduces anytime by simply running the given PoC on the given Node.js version.

What is the expected behavior? Why is that the expected behavior?

It is a crash.

What do you see instead?

FATAL ERROR: v8::ToLocalChecked Empty MaybeLocal

Additional information

No response

Activity

  1. joyeecheung commented on Jan 10, 2025

    @joyeecheung
    Member

    In general we provide no guarantee about the usability of the process once builtin prototypes like this are modified, so it's not technically a bug, but poor UX at worst. It would be a UX improvement to at least not crash, if it's not too invasive a change to defend against it.

    Marking as good first issues, though just for those who are willing to debug the C++ internals.

  2. added
    good first issueIssues that are suitable for first-time contributors.
    c++Issues and PRs that require attention from people who are familiar with C++.
    child_processIssues and PRs related to the child_process subsystem.
    on Jan 10, 2025
  3. cristianstaicu commented on Jan 13, 2025

    @cristianstaicu

    Thanks for the clarification! Imo, crashing the runtime like this is always bad. We had a discussion a while back about supporting the execution of untrusted code in Node.js: #40718. While not necessary true for this particular payload shared by @vdata1 because of the privileged child_process API call, but imagine a use case like Cloudflare's Workers (https://developers.cloudflare.com/workers/reference/security-model/) in which mutually untrusted, low-privilege code share the same process. Attackers can crash co-located Isolates with such payloads. What is the team's view on this? Are these assumptions well documented somewhere?

  4. joyeecheung commented on Jan 13, 2025

    @joyeecheung
    Member

    but imagine a use case like Cloudflare's Workers in which mutually untrusted, low-privilege code share the same process.

    You are referencing cloudflare's security model, which differs from the Node.js threat model.

    Node.js trusts everything else. Examples include:
    ...
    The code it is asked to run, including JavaScript, WASM and native code, even if said code is dynamically loaded, e.g., all dependencies installed from the npm registry. The code run inherits all the privileges of the execution user.

    Like vm, child_process is just another regular API that should not be accessible to untrusted code. If a Node.js application allows code provided by a potential attacker to run in the process, the security risk is on them, not on Node.js. Using Node.js for an architecture similar to cloudflare's worker is in itself, a design with security flaws, as Node.js was never built with this security model in mind and after >10 years of organic growth, it would have countless loopholes even if one wants to start amending it for this model now, so it's already a lost cause.

  5. joyeecheung commented on Jan 13, 2025

    @joyeecheung
    Member

    (github button mistakes)

  6. cristianstaicu commented on Jan 13, 2025

    @cristianstaicu

    Wow, that is a very bold claim in Node.js' threat model! "Node.js trusts everything else. Examples include: ... The code it is asked to run." 😄 Sure, I am aware that Cloudflare runs on a dedicated runtime, not on Node.js, that is why I said "a use case like". Nonetheless, many of us thought that running untrusted code inside a worker or something like isolated-vm is probably safe (see the discussion I linked above). However, that is only the case if the runtime is crash-resilient against arbitrary code, which you say the team does not aim to guarantee. I now see that the isolated-vm project is struggling exactly with this type of issues: https://github.com/laverdet/isolated-vm?tab=readme-ov-file#wishlist

  7. cristianstaicu commented on Jan 13, 2025

    @cristianstaicu

    Thanks for the updated comment above. If I understand correctly, it is the combination of a privileged/Node.js API with a crash that makes this a low-priority issue, then. If the same effect can be obtained by a modified prototype like above with something like Math.log(), that would be more interesting for you guys; but, then, we would likely need to take such issues to the v8 team directly. 😄

  8. hohwille commented on Sep 19, 2025

    @hohwille

    Happens a lot for plugin installations in Visual Studio Code:

    Start: Install plugin project-manager
    Running command 'D:\projects\_ide\software\default\vscode\vscode\1.104.1\bin\code.cmd' with arguments '--new-window' '--user-data-dir=D:\projects\IDEasy\workspaces\main\.vscode\.userdata' '--extensions-dir=D:\projects\IDEasy\plugins\vscode' 'D:\projects\IDEasy\workspaces\main' '--force' '--install-extension' 'alefragnani.project-manager'
    failed with exit code 134!
    Installing extensions...
    Installing extension 'alefragnani.project-manager'...
    Extension 'alefragnani.project-manager' v12.8.0 was successfully installed.
    FATAL ERROR: v8::ToLocalChecked Empty MaybeLocal
    ----- Native stack trace -----
    
     1: 00007FF7DF3DB4AA llhttp_get_upgrade+41370
     2: 00007FF7DF4B6262 node::OnFatalError+290
     3: 00007FF7E48E7D8C v8::Function::NewInstance+540
     4: 00007FF7E48E82C4 v8::api_internal::ToLocalEmpty+20
     5: 00007FF7DF52CC67 uv_loop_fork+448279
     6: 00007FF7DF530B76 uv_loop_fork+464422
     7: 00007FF7E33C5E74 v8::internal::compiler::CompilationDependencies::FieldTypeDependencyOffTheRecord+2356100
     8: 00007FF7B8ECE198
    
    ----- JavaScript stack trace -----
    
    1: getPackageScopeConfig (node:internal/modules/package_json_reader:149:33)
    2: getPackageJSONURL (node:internal/modules/package_json_reader:225:25)
    3: packageResolve (node:internal/modules/esm/resolve:779:81)
    4: moduleResolve (node:internal/modules/esm/resolve:865:18)
    5: defaultResolve (node:internal/modules/esm/resolve:995:11)
    6: nextResolve (node:internal/modules/esm/hooks:748:28)
    7: resolve (data:text/javascript;base64,CglleHBvcnQgYXN5bmMgZnVuY3Rpb24gcmVzb2x2ZShzcGVjaWZpZXIsIGNvbnRleHQsIG5leHRSZXNvbHZlKSB7CgkJaWYgKHNwZWNpZmllciA9PT0gJ2ZzJykgewoJCQlyZXR1cm4gewoJCQkJZm9ybWF0OiAnYnVpbHRpbicsCgkJCQlzaG9ydENpcmN1aXQ6IHRydWUsCgkJCQl1cmw6ICdub2RlOm9yaWdpbmFsLWZzJwoJCQl9OwoJCX0KCgkJLy8gRGVmZXIgdG8gdGhlIG5leHQgaG9vayBpbiB0aGUgY2hhaW4sIHdoaWNoIHdvdWxkIGJlIHRoZQoJCS8vIE5vZGUuanMgZGVmYXVsdCByZXNvbHZlIGlmIHRoaXMgaXMgdGhlIGxhc3QgdXNlci1zcGVjaWZpZWQgbG9hZGVyLgoJCXJldHVybiBuZXh0UmVzb2x2ZShzcGVjaWZpZXIsIGNvbnRleHQpOwoJfQ==:13:10)
    8: nextResolve (node:internal/modules/esm/hooks:748:28)
    9: resolve (node:internal/modules/esm/hooks:240:30)
    10: handleMessage (node:internal/modules/esm/worker:199:24)
    
    
    Running command 'D:\projects\_ide\software\default\vscode\vscode\1.104.1\bin\code.cmd' with arguments '--new-window' '--user-data-dir=D:\projects\IDEasy\workspaces\main\.vscode\.userdata' '--extensions-dir=D:\projects\IDEasy\plugins\vscode' 'D:\projects\IDEasy\workspaces\main' '--force' '--install-extension' 'alefragnani.project-manager'
    failed with exit code 134!
    Step 'Install plugin project-manager' ended with failure.
    Start: Install plugin asciidoctor
    Running command 'D:\projects\_ide\software\default\vscode\vscode\1.104.1\bin\code.cmd' with arguments '--new-window' '--user-data-dir=D:\projects\IDEasy\workspaces\main\.vscode\.userdata' '--extensions-dir=D:\projects\IDEasy\plugins\vscode' 'D:\projects\IDEasy\workspaces\main' '--force' '--install-extension' 'asciidoctor.asciidoctor-vscode'
    failed with exit code 134!
    Installing extensions...
    Installing extension 'asciidoctor.asciidoctor-vscode'...
    Extension 'asciidoctor.asciidoctor-vscode' v3.4.5 was successfully installed.
    FATAL ERROR: v8::ToLocalChecked Empty MaybeLocal
    ----- Native stack trace -----
    
     1: 00007FF7DF3DB4AA llhttp_get_upgrade+41370
     2: 00007FF7DF4B6262 node::OnFatalError+290
     3: 00007FF7E48E7D8C v8::Function::NewInstance+540
     4: 00007FF7E48E82C4 v8::api_internal::ToLocalEmpty+20
     5: 00007FF7DF52CC67 uv_loop_fork+448279
     6: 00007FF7DF530B76 uv_loop_fork+464422
     7: 00007FF7E33C5E74 v8::internal::compiler::CompilationDependencies::FieldTypeDependencyOffTheRecord+2356100
     8: 00007FF7B8ECE198
    
    ----- JavaScript stack trace -----
    
    1: getPackageScopeConfig (node:internal/modules/package_json_reader:149:33)
    2: getPackageJSONURL (node:internal/modules/package_json_reader:225:25)
    3: packageResolve (node:internal/modules/esm/resolve:779:81)
    4: moduleResolve (node:internal/modules/esm/resolve:865:18)
    5: defaultResolve (node:internal/modules/esm/resolve:995:11)
    6: nextResolve (node:internal/modules/esm/hooks:748:28)
    7: resolve (data:text/javascript;base64,CglleHBvcnQgYXN5bmMgZnVuY3Rpb24gcmVzb2x2ZShzcGVjaWZpZXIsIGNvbnRleHQsIG5leHRSZXNvbHZlKSB7CgkJaWYgKHNwZWNpZmllciA9PT0gJ2ZzJykgewoJCQlyZXR1cm4gewoJCQkJZm9ybWF0OiAnYnVpbHRpbicsCgkJCQlzaG9ydENpcmN1aXQ6IHRydWUsCgkJCQl1cmw6ICdub2RlOm9yaWdpbmFsLWZzJwoJCQl9OwoJCX0KCgkJLy8gRGVmZXIgdG8gdGhlIG5leHQgaG9vayBpbiB0aGUgY2hhaW4sIHdoaWNoIHdvdWxkIGJlIHRoZQoJCS8vIE5vZGUuanMgZGVmYXVsdCByZXNvbHZlIGlmIHRoaXMgaXMgdGhlIGxhc3QgdXNlci1zcGVjaWZpZWQgbG9hZGVyLgoJCXJldHVybiBuZXh0UmVzb2x2ZShzcGVjaWZpZXIsIGNvbnRleHQpOwoJfQ==:13:10)
    8: nextResolve (node:internal/modules/esm/hooks:748:28)
    9: resolve (node:internal/modules/esm/hooks:240:30)
    10: handleMessage (node:internal/modules/esm/worker:199:24)
    
    
    Running command 'D:\projects\_ide\software\default\vscode\vscode\1.104.1\bin\code.cmd' with arguments '--new-window' '--user-data-dir=D:\projects\IDEasy\workspaces\main\.vscode\.userdata' '--extensions-dir=D:\projects\IDEasy\plugins\vscode' 'D:\projects\IDEasy\workspaces\main' '--force' '--install-extension' 'asciidoctor.asciidoctor-vscode'
    failed with exit code 134!
    Step 'Install plugin asciidoctor' ended with failure.
    

    Also for pretty-ts-errors plugin.

  9. shikhindahikar commented on Oct 3, 2025

    @shikhindahikar

    is this issue still open?

  10. zhanglinqian commented on Feb 12, 2026

    @zhanglinqian

    I'd like to work on this issue.

  11. WolffM commented on Feb 16, 2026

    @WolffM

    Hello! I'm looking for ways to contribute to to nodejs, can i be assigned to work on this?

  12. dhruv7539 commented on Feb 25, 2026

    @dhruv7539

    Opened a fix PR here: https://github.com/nodejs/node/pull/61978\n\nThis adds validation for non-object stdio entries in ProcessWrap::ParseStdioOptions() and includes a regression test for the Array.prototype setter pollution case.

  13. github-actions commented on Jul 20, 2026

    @github-actions
    Contributor

    This issue has been marked as stale due to 90 days of inactivity.
    It will be automatically closed in 30 days if no further activity occurs. If this is still relevant, please leave a comment or update it to keep it open.

  14. added
    staleIssues and PRs marked stale due to inactivity and scheduled for automatic closure.
    on Jul 20, 2026
  15. saitejabandaru-in commented on Jul 30, 2026

    @saitejabandaru-in

    Thanks for the report! I was able to reproduce this. Modifying Array.prototype[2] (or Array.prototype in general) breaks internal C++ assumptions when V8 arrays are constructed or accessed (often seen in child_process when arguments/env arrays are being converted to V8 arrays). The ToLocalChecked() failure happens because V8 throws a JS exception when setting the element, resulting in an empty MaybeLocal. Node core usually protects against this by using SetRealNamedProperty or ensuring prototype pollution doesn't break array initialization. I will try to track down the exact V8 call in src/node_child_process.cc or src/env.cc that is throwing.

  16. removed
    staleIssues and PRs marked stale due to inactivity and scheduled for automatic closure.
    on Jul 31, 2026
  17. AaradhyAdhikari commented on Aug 1, 2026

    @AaradhyAdhikari

    Hi! I’m interested in investigating this issue as my first contribution to Node.js. Before I begin, could a maintainer please confirm whether the issue is still open for contribution and point me toward any relevant files or tests I should review? Thank you!

  18. HesamDanaee commented on Aug 3, 2026

    @HesamDanaee

    I would like to contribute with this as my first issue.

  19. jaydaVis04 commented on Aug 6, 2026

    @jaydaVis04

    Hi, I’d like to investigate this issue. I plan to reproduce the crash on the current main branch, trace where an empty MaybeLocal reaches ToLocalChecked, determine whether the affected child-process path can handle the failure without terminating the runtime, and add a regression test for the provided reproduction. Is anyone currently working on this, and would maintainers prefer an initial diagnostic PR or a complete fix?

  20. added a commit that references this issue on Aug 29, 2026
    c66e802
  21. LeonxLJX commented on Sep 1, 2026

    @LeonxLJX
  22. added a commit that references this issue on Sep 4, 2026
    a329954
  23. viktor-podzigun commented on Sep 14, 2026

    @viktor-podzigun

    In more recent version of Node the above example from the issue description is throwing the following error now:

    % node test.js
    node:internal/child_process:396
      const err = this._handle.spawn(options);
                               ^
    
    TypeError: Cannot read properties of undefined (reading 'type')
        at ChildProcess.spawn (node:internal/child_process:396:28)
        at spawn (node:child_process:796:9)
        at Object.execFile (node:child_process:349:17)
        at exec (node:child_process:236:25)
        at /Users/viktorpodzigun/workspace/test/test.js:8:3
        at Object.<anonymous> (/Users/viktorpodzigun/workspace/test/test.js:11:3)
        at Module._compile (node:internal/modules/cjs/loader:1812:14)
        at Object..js (node:internal/modules/cjs/loader:1943:10)
        at Module.load (node:internal/modules/cjs/loader:1533:32)
        at Module._load (node:internal/modules/cjs/loader:1335:12)
    
    Node.js v24.14.0

    Bun is also freezing in this case: oven-sh/bun#42723

    What should be the proper handling then? Should warning also be written to the console when modifying Array prototype? 🤔

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    c++Issues and PRs that require attention from people who are familiar with C++.child_processIssues and PRs related to the child_process subsystem.good first issueIssues that are suitable for first-time contributors.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions