Vulnerability: Denial of Service in node-sass Affected versions of `node-sass` are vulnerable to Denial of Service (DoS). Crafted objects passed to the `renderSync` function may trigger C++ assertions in `CustomImporterBridge::get_importer_entry` and `CustomImporterBridge::post_process_return_value` that crash the Node process. This may allow attackers to crash the system's running Node process and lead to Denial of Service.


## Recommendation

Upgrade to version 4.13.1 or later
Vulnerability ID: GHSA-9v62-24cr-58cx
CWE: CWE-400
Severity score: 5.9
Project: https://github.com/sass/node-sass
Published: 2020-09-11
File: src/custom_importer_bridge.cpp
Commit message: Merge pull request from GHSA-f6rp-gv58-9cw3
Commit author: Michael Mifsud

Vulnerable version (before fix):
 SassImportList CustomImporterBridge::post_process_return_value(v8::Local<v8::Val     imports = sass_make_import_list(array->Length());      for (size_t i = 0; i < array->Length(); ++i) {       v8::Local<v8::Value> value = Nan::Get(array, static_cast<uint32_t>(i)).ToLocalChecked();        if (!value->IsObject()) {         auto entry = sass_make_import_entry(0, 0, 0);         sass_import_set_error(entry, "returned array must only contain object literals", -1, -1);         continue;       }  Sass_Import* CustomImporterBridge::check_returned_string(Nan::MaybeLocal<v8::Val }  Sass_Import* CustomImporterBridge::get_importer_entry(const v8::Local<v8::Object>& object) const {   auto returned_file = Nan::Get(object, Nan::New<v8::String>("file").ToLocalChecked());   auto returned_contents = Nan::Get(object, Nan::New<v8::String>("contents").ToLocalChecked()).ToLocalChecked();   auto returned_map = Nan::Get(object, Nan::New<v8::String>("map").ToLocalChecked());   Sass_Import *err;    if ((err = check_returned_string(returned_file, "returned value of `file` must be a string")))

Fixed version (after fix):
 SassImportList CustomImporterBridge::post_process_return_value(v8::Local<v8::Val     imports = sass_make_import_list(array->Length());      for (size_t i = 0; i < array->Length(); ++i) {       v8::Local<v8::Value> value;       Nan::MaybeLocal<v8::Value> unchecked = Nan::Get(array, static_cast<uint32_t>(i));        if (!unchecked.ToLocal(&value) || !value->IsObject()) {         imports[i] = sass_make_import_entry(0, 0, 0);         sass_import_set_error(imports[i], "returned array must only contain object literals", -1, -1);         continue;       }  Sass_Import* CustomImporterBridge::check_returned_string(Nan::MaybeLocal<v8::Val }  Sass_Import* CustomImporterBridge::get_importer_entry(const v8::Local<v8::Object>& object) const {   Nan::MaybeLocal<v8::Value> returned_file = Nan::Get(object, Nan::New<v8::String>("file").ToLocalChecked());   Nan::MaybeLocal<v8::Value> returned_contents = Nan::Get(object, Nan::New<v8::String>("contents").ToLocalChecked());   Nan::MaybeLocal<v8::Value> returned_map = Nan::Get(object, Nan::New<v8::String>("map").ToLocalChecked());   Sass_Import *err;    if ((err = check_returned_string(returned_file, "returned value of `file` must be a string")))

Patch:
patch: @@ -13,11 +13,12 @@ SassImportList CustomImporterBridge::post_process_return_value(v8::Local<v8::Val
     imports = sass_make_import_list(array->Length());
 
     for (size_t i = 0; i < array->Length(); ++i) {
-      v8::Local<v8::Value> value = Nan::Get(array, static_cast<uint32_t>(i)).ToLocalChecked();
+      v8::Local<v8::Value> value;
+      Nan::MaybeLocal<v8::Value> unchecked = Nan::Get(array, static_cast<uint32_t>(i));
 
-      if (!value->IsObject()) {
-        auto entry = sass_make_import_entry(0, 0, 0);
-        sass_import_set_error(entry, "returned array must only contain object literals", -1, -1);
+      if (!unchecked.ToLocal(&value) || !value->IsObject()) {
+        imports[i] = sass_make_import_entry(0, 0, 0);
+        sass_import_set_error(imports[i], "returned array must only contain object literals", -1, -1);
         continue;
       }
 
@@ -71,9 +72,9 @@ Sass_Import* CustomImporterBridge::check_returned_string(Nan::MaybeLocal<v8::Val
 }
 
 Sass_Import* CustomImporterBridge::get_importer_entry(const v8::Local<v8::Object>& object) const {
-  auto returned_file = Nan::Get(object, Nan::New<v8::String>("file").ToLocalChecked());
-  auto returned_contents = Nan::Get(object, Nan::New<v8::String>("contents").ToLocalChecked()).ToLocalChecked();
-  auto returned_map = Nan::Get(object, Nan::New<v8::String>("map").ToLocalChecked());
+  Nan::MaybeLocal<v8::Value> returned_file = Nan::Get(object, Nan::New<v8::String>("file").ToLocalChecked());
+  Nan::MaybeLocal<v8::Value> returned_contents = Nan::Get(object, Nan::New<v8::String>("contents").ToLocalChecked());
+  Nan::MaybeLocal<v8::Value> returned_map = Nan::Get(object, Nan::New<v8::String>("map").ToLocalChecked());
   Sass_Import *err;
 
   if ((err = check_returned_string(returned_file, "returned value of `file` must be a string")))
path: src/custom_importer_bridge.cpp