Node.js has released updates for a high severity vulnerability that could be exploited by attackers to corrupt the process and cause unexpected behaviors, such as application crashes and potentially remote code execution (RCE).
The use-after-free vulnerability, tracked as CVE-2021-22930 is to do with how HTTP2 streams are handled in the language.
Node.js pushes out immediate fixes for the flaw
This week Node.js has pushed out fixes for high severity, use-after-free vulnerability, tracked as CVE-2021-22930.
Use-after-free vulnerabilities occur when a program tries to access a resource at a memory address that has been previously freed and no longer holds the resource.
This can lead to data corruption, or unexpected behaviors such as application crashes, or even remote code execution (RCE) in some cases.
The fixes landed in the latest Node.js release 16.6.0 and were also backported to versions 12.22.4 (LTS) and 14.17.4 (LTS).
The fix shown below has been applied across multiple Node.js branches to squash the use-after-free vulnerability:
Eran Levin has been credited with reporting this vulnerability.
The abrupt update release for a high severity vulnerability is explained by the fact discussions around the vulnerability were already public:
“We normally like to give advance notice and provide releases in which the only changes are security fixes, but since this vulnerability was already public we felt it was more important to get this fix out fast in releases that were already planned,” announced Red Hat principal software engineer and NodeJS Technical Steering Committee (TSC) member Daniel Bevenius.
Bug triggered when aborting HTTP connections
The vulnerability was triggered in cases where Node.js parsed incoming RST_STREAM frames, with no error code or a cancel code.
In applications based on the HTTP/2 protocol, RST_STREAM frame is sent by either host intending to terminate a connection.
For example, in a client-server architecture, if a client application wants to end the connection, it would send an RST_STREAM frame to the server.
On receiving the frame, the server will cease responding to the client, eventually aborting the connection. Any “DATA” frames which the server was about to send to the client, could then be discarded.
But in the case of vulnerable Node.js versions, when an RST_STREAM frame was received by the server with a “cancel” code (nghttp2_cancel), the receiver would try to “force purge” any data received.
And, once this was done, an automatic callback would additionally run the “close” function, attempting to free up the memory a second time—which had already been freed in the last step.
And, this would result in an application crash, or erratic behavior due to a double-free error.
This error—previously thought of as a “bug” rather than an exploitable vulnerability, was reported on June 8th, 2021 by Matthew Douglass on a public thread.
Douglass was able to reproduce the bug 100% of the time on his system, resulting in application crashes.
The discussion ensued for well over a month between Douglass and Node.js contributors:
“The issue seems to be because of the handling of the RST_STREAM frame received with no error code and cancel error code.”
“The node tries to force process it and purge any existing data for the stream. This causes nghttp2 to close the already destroyed stream causing the double-free error,” responded GitHub user kumarak.
The fix rolled out instead adds the incoming stream of RST_STREAM frames to a queue and processes the queue once it is safe to do so. This would prevent any double-free or use-after-free errors.