CVE-2022-25885: Insufficient Information (NVD-CWE-noinfo)
value: The package muhammara before 2.6.0; all versions of package hummus are vulnerable to Denial of Service (DoS) when PDFStreamForResponse() is used with invalid data.
CWE description: There is insufficient information about the issue to classify it; details are unkown or unspecified.
CVSS v3 base score: 7.5
Published: 2022-11-01T05:15Z
Repository: https://github.com/julianhille/MuhammaraJS
Language: C++
Files changed: CHANGELOG.md, src/ObjectByteWriterWithPosition.cpp, tests/BasicModificationWithStreams.js
Commit date: 2022-06-30 00:54:39 +0200
Commit message: Fix createWriter cpp / crash / npe when using null as stream object (#190)

Fix createWriter cpp / crash / npe when using null as stream object

Fixes #188
Diff: diff --git a/CHANGELOG.md b/CHANGELOG.md
index a42a927..16ad5e9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,10 +7,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
 
 ## [Unreleased]
 
 ### Changed
 
+- Fixes hard crash to exception when creating a stream with null object and calling createWriter with it
 - Fixes missing buffer information for recrypt typescript definition
 
 ## [2.5.0] - 2022-06-23
 
 ### Added
diff --git a/src/ObjectByteWriterWithPosition.cpp b/src/ObjectByteWriterWithPosition.cpp
index 231d7ca..1e8978f 100644
--- a/src/ObjectByteWriterWithPosition.cpp
+++ b/src/ObjectByteWriterWithPosition.cpp
@@ -50,25 +50,33 @@ IOBasicTypes::LongBufferSizeType ObjectByteWriterWithPosition::Write(const IOBas
     }
     Local<Function> func = Local<Function>::Cast(value);
     
     Local<Value> args[1];
     args[0] = anArray;
-    
-	Local<Value> result = func->Call(GET_CURRENT_CONTEXT,  OBJECT_FROM_PERSISTENT(mObject), 1, args).ToLocalChecked();
+    MaybeLocal<Value> maybe;
+    TryCatch try_catch(Isolate::GetCurrent());
+
+    maybe = func->Call(GET_CURRENT_CONTEXT,  OBJECT_FROM_PERSISTENT(mObject), 1, args);
+    Local <Value> result;
+
+    if (!maybe.ToLocal(&result)) {
+       try_catch.ReThrow();
+       return 0;
+    }
     if(result.IsEmpty())
     {
-		THROW_EXCEPTION("wrong return value. it's empty. return the number of written characters");
-		return 0;
+        THROW_EXCEPTION("wrong return value. it's empty. return the number of written characters");
+        return 0;
     }
     else if(result->IsNumber())
     {
         return TO_UINT32(result)->Value();
     }
     else
     {
-		THROW_EXCEPTION("wrong return value. write should return the number of written characters");
-		return 0;
+        THROW_EXCEPTION("wrong return value. write should return the number of written characters");
+        return 0;
     }
 }
 
 IOBasicTypes::LongFilePositionType ObjectByteWriterWithPosition::GetCurrentPosition()
 {
@@ -79,6 +87,6 @@ IOBasicTypes::LongFilePositionType ObjectByteWriterWithPosition::GetCurrentPosit
     if(value->IsUndefined())
         return true;
     Local<Function> func = Local<Function>::Cast(value);
     
 	return TO_NUMBER(func->Call(GET_CURRENT_CONTEXT, OBJECT_FROM_PERSISTENT(mObject), 0, NULL).ToLocalChecked())->Value();
-}
\ No newline at end of file
+}
diff --git a/tests/BasicModificationWithStreams.js b/tests/BasicModificationWithStreams.js
index 8971979..80087b1 100644
--- a/tests/BasicModificationWithStreams.js
+++ b/tests/BasicModificationWithStreams.js
@@ -1,6 +1,7 @@
 var muhammara = require('../muhammara');
+const chai = require('chai');
 
 describe('BasicModificationWithStreams', function() {
 	it('should complete without error', function() {
 		var inStream = new muhammara.PDFRStreamForFile(__dirname + '/TestMaterials/MultipleChange.pdf');
 		var outStream = new muhammara.PDFWStreamForFile(__dirname + '/output/BasicModificationWithStreams.pdf');
@@ -12,11 +13,17 @@ describe('BasicModificationWithStreams', function() {
 			size:14,
 			colorspace:'gray',
 			color:0x00
 		});
 		pageModifier.endContext().writePage();
-
 		pdfWriter.end();
 		outStream.close();
 		inStream.close();
 	});
+
+	it('null for stream should throw an error and not crash', function () {
+		var res = new muhammara.PDFStreamForResponse(null)
+		chai.expect(
+			muhammara.createWriter.bind(undefined, res)
+		).to.throw(/Cannot read propert.*(write)?.* of null/)
+	})
 });

Vulnerable code:     
	Local<Value> result = func->Call(GET_CURRENT_CONTEXT,  OBJECT_FROM_PERSISTENT(mObject), 1, args).ToLocalChecked();
		THROW_EXCEPTION("wrong return value. it's empty. return the number of written characters");
		return 0;
		THROW_EXCEPTION("wrong return value. write should return the number of written characters");
		return 0;
}

Fixed code: - Fixes hard crash to exception when creating a stream with null object and calling createWriter with it
    MaybeLocal<Value> maybe;
    TryCatch try_catch(Isolate::GetCurrent());

    maybe = func->Call(GET_CURRENT_CONTEXT,  OBJECT_FROM_PERSISTENT(mObject), 1, args);
    Local <Value> result;

    if (!maybe.ToLocal(&result)) {
       try_catch.ReThrow();
       return 0;
    }
        THROW_EXCEPTION("wrong return value. it's empty. return the number of written characters");
        return 0;
        THROW_EXCEPTION("wrong return value. write should return the number of written characters");
        return 0;
}
const chai = require('chai');

	it('null for stream should throw an error and not crash', function () {
		var res = new muhammara.PDFStreamForResponse(null)
		chai.expect(
			muhammara.createWriter.bind(undefined, res)
		).to.throw(/Cannot read propert.*(write)?.* of null/)
	})