High severity8.8NVD Advisory· Published Jun 16, 2016· Updated May 6, 2026
CVE-2016-3199
CVE-2016-3199
Description
The Chakra JavaScript engine in Microsoft Edge allows remote attackers to execute arbitrary code or cause a denial of service (memory corruption) via a crafted web site, aka "Scripting Engine Memory Corruption Vulnerability," a different vulnerability than CVE-2016-3214.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
Microsoft.ChakraCoreNuGet | < 1.2.0.0 | 1.2.0.0 |
Affected products
1Patches
1bcd950efee48TypedArrayCreate for TypedArray built-in methods
5 files changed · +115 −68
lib/Runtime/Library/JavascriptArray.cpp+6 −4 modified@@ -5767,7 +5767,7 @@ namespace Js newArr = CreateNewArrayHelper(static_cast<uint32>(newLenT), isIntArray, isFloatArray, pArr, scriptContext); newObj = newArr; } - else if (JavascriptOperators::IsConstructor(constructor) && JavascriptLibrary::IsTypedArrayConstructor(constructor, scriptContext)) + else if (JavascriptOperators::IsConstructor(constructor)) { if (pArr) { @@ -5778,7 +5778,7 @@ namespace Js Js::Var constructorArgs[] = { constructor, JavascriptNumber::ToVar(newLenT, scriptContext) }; Js::CallInfo constructorCallInfo(Js::CallFlags_New, _countof(constructorArgs)); - newObj = RecyclableObject::FromVar(JavascriptOperators::NewScObject(constructor, Js::Arguments(constructorCallInfo, constructorArgs), scriptContext)); + newObj = RecyclableObject::FromVar(TypedArrayBase::TypedArrayCreate(constructor, &Js::Arguments(constructorCallInfo, constructorArgs), (uint32)newLenT, scriptContext)); } else { @@ -8832,7 +8832,7 @@ namespace Js { Js::Var constructorArgs[] = { constructor, JavascriptNumber::ToVar(length, scriptContext) }; Js::CallInfo constructorCallInfo(Js::CallFlags_New, _countof(constructorArgs)); - newObj = RecyclableObject::FromVar(JavascriptOperators::NewScObject(constructor, Js::Arguments(constructorCallInfo, constructorArgs), scriptContext)); + newObj = RecyclableObject::FromVar(TypedArrayBase::TypedArrayCreate(constructor, &Js::Arguments(constructorCallInfo, constructorArgs), (uint32)length, scriptContext)); } else if (isTypedArrayEntryPoint) { @@ -9788,7 +9788,9 @@ namespace Js Js::Var constructorArgs[] = { constructor, JavascriptNumber::ToVar(len, scriptContext) }; Js::CallInfo constructorCallInfo(Js::CallFlags_New, _countof(constructorArgs)); - newObj = JavascriptOperators::NewScObject(constructor, Js::Arguments(constructorCallInfo, constructorArgs), scriptContext); + newObj = isTypedArrayEntryPoint ? + TypedArrayBase::TypedArrayCreate(constructor, &Js::Arguments(constructorCallInfo, constructorArgs), len, scriptContext) : + JavascriptOperators::NewScObject(constructor, Js::Arguments(constructorCallInfo, constructorArgs), scriptContext); // If the new object we created is an array, remember that as it will save us time setting properties in the object below if (JavascriptArray::Is(newObj))
lib/Runtime/Library/TypedArray.cpp+38 −4 modified@@ -1361,7 +1361,7 @@ namespace Js Js::Var constructorArgs[] = { constructor, buffer, JavascriptNumber::ToVar(beginByteOffset, scriptContext), JavascriptNumber::ToVar(newLength, scriptContext) }; Js::CallInfo constructorCallInfo(Js::CallFlags_New, _countof(constructorArgs)); - newTypedArray = JavascriptOperators::NewScObject(constructor, Js::Arguments(constructorCallInfo, constructorArgs), scriptContext); + newTypedArray = RecyclableObject::FromVar(TypedArrayBase::TypedArrayCreate(constructor, &Js::Arguments(constructorCallInfo, constructorArgs), newLength, scriptContext)); } else { @@ -1447,7 +1447,7 @@ namespace Js Js::Var constructorArgs[] = { constructor, JavascriptNumber::ToVar(len, scriptContext) }; Js::CallInfo constructorCallInfo(Js::CallFlags_New, _countof(constructorArgs)); - newObj = JavascriptOperators::NewScObject(constructor, Js::Arguments(constructorCallInfo, constructorArgs), scriptContext); + newObj = TypedArrayBase::TypedArrayCreate(constructor, &Js::Arguments(constructorCallInfo, constructorArgs), len, scriptContext); TypedArrayBase* newTypedArrayBase = nullptr; JavascriptArray* newArr = nullptr; @@ -1511,7 +1511,7 @@ namespace Js Js::Var constructorArgs[] = { constructor, JavascriptNumber::ToVar(len, scriptContext) }; Js::CallInfo constructorCallInfo(Js::CallFlags_New, _countof(constructorArgs)); - newObj = JavascriptOperators::NewScObject(constructor, Js::Arguments(constructorCallInfo, constructorArgs), scriptContext); + newObj = TypedArrayBase::TypedArrayCreate(constructor, &Js::Arguments(constructorCallInfo, constructorArgs), len, scriptContext); TypedArrayBase* newTypedArrayBase = nullptr; JavascriptArray* newArr = nullptr; @@ -1770,7 +1770,7 @@ namespace Js Js::Var constructorArgs[] = { constructor, JavascriptNumber::ToVar(captured, scriptContext) }; Js::CallInfo constructorCallInfo(Js::CallFlags_New, _countof(constructorArgs)); - newObj = RecyclableObject::FromVar(JavascriptOperators::NewScObject(constructor, Js::Arguments(constructorCallInfo, constructorArgs), scriptContext)); + newObj = RecyclableObject::FromVar(TypedArrayBase::TypedArrayCreate(constructor, &Js::Arguments(constructorCallInfo, constructorArgs), captured, scriptContext)); if (TypedArrayBase::Is(newObj)) { @@ -2733,6 +2733,40 @@ namespace Js return Js::JavascriptNumber::ToVarNoCheck(currentRes, scriptContext); } + // static + Var TypedArrayBase::ValidateTypedArray(Var aValue, ScriptContext *scriptContext) + { + if (!TypedArrayBase::Is(aValue)) + { + JavascriptError::ThrowTypeError(scriptContext, JSERR_This_NeedTypedArray); + } + + TypedArrayBase *typedArrayBase = TypedArrayBase::FromVar(aValue); + ArrayBuffer *arrayBuffer = typedArrayBase->GetArrayBuffer(); + if (arrayBuffer->IsDetached()) + { + JavascriptError::ThrowTypeError(scriptContext, JSERR_DetachedTypedArray); + } + + return arrayBuffer; + } + + // static + Var TypedArrayBase::TypedArrayCreate(Var constructor, Arguments *args, uint32 length, ScriptContext *scriptContext) + { + Var newObj = JavascriptOperators::NewScObject(constructor, *args, scriptContext); + + TypedArrayBase::ValidateTypedArray(newObj, scriptContext); + + // ECMA262 22.2.4.6 TypedArrayCreate line 3. "If argumentList is a List of a single Number" (args[0] == constructor) + if (args->Info.Count == 2 && TypedArrayBase::FromVar(newObj)->GetLength() < length) + { + JavascriptError::ThrowTypeError(scriptContext, JSERR_InvalidTypedArrayLength); + } + + return newObj; + } + template<> BOOL Uint8ClampedArray::Is(Var aValue) { return JavascriptOperators::GetTypeId(aValue) == TypeIds_Uint8ClampedArray &&
lib/Runtime/Library/TypedArray.h+2 −0 modified@@ -137,6 +137,8 @@ namespace Js // Returns false if this is not a TypedArray or it's not detached static BOOL IsDetachedTypedArray(Var aValue); static HRESULT GetBuffer(Var aValue, ArrayBuffer** outBuffer, uint32* outOffset, uint32* outLength); + static Var ValidateTypedArray(Var aValue, ScriptContext *scriptContext); + static Var TypedArrayCreate(Var constructor, Arguments *args, uint32 length, ScriptContext *scriptContext); virtual BOOL DirectSetItem(__in uint32 index, __in Js::Var value) = 0; virtual BOOL DirectSetItemNoSet(__in uint32 index, __in Js::Var value) = 0;
test/es6/ES6TypedArrayExtensions.js+28 −60 modified@@ -485,11 +485,11 @@ var tests = [ body: function() { var fromFnc = Uint8Array.__proto__.from; - var b = fromFnc.call(Array, "string"); - assert.areEqual('object', typeof b, "%TypedArray%.from.call(Array, 'string') returns an array"); - assert.areEqual(['s','t','r','i','n','g'], b, "%TypedArray%.from.call(Array, 'string') == ['s','t','r','i','n','g']"); - assert.areEqual(6, b.length, "%TypedArray%.from.call(Array, 'string').length === 6"); - assert.isFalse(ArrayBuffer.isView(b), "%TypedArray%.from.call(Array, 'string') is not a TypedArray"); + var b = fromFnc.call(Float64Array, [1,2,3,4,5,6]); + assert.areEqual('object', typeof b, "%TypedArray%.from.call(Float64Array, 'string') returns a Float64Array"); + assert.areEqual([1,2,3,4,5,6], b, "%TypedArray%.from.call(Float64Array, 'string') == [1,2,3,4,5,6]"); + assert.areEqual(6, b.length, "%TypedArray%.from.call(Float64Array, 'string').length === 6"); + assert.isTrue(ArrayBuffer.isView(b) && b instanceof Float64Array, "%TypedArray%.from.call(Float64Array, 'string') is a Float64Array"); var a = { 0: 0, 1: 1, 2: 2, length: 5 }; var b = fromFnc.call(Uint8Array, a); @@ -499,18 +499,18 @@ var tests = [ assert.areEqual([0,1,2,0,0], b, "Uint8Array.from(objectWithLengthProperty) has missing values set to 0"); var a = { 0: 0, 1: 1, 2: 2, length: 5 }; - var b = fromFnc.call(Array, a); - assert.areEqual('object', typeof b, "%TypedArray%.from.call(Array, objectWithLengthProperty) returns an object"); - assert.areEqual(5, b.length, "%TypedArray%.from.call(Array, objectWithLengthProperty) returns a new array with length = a.length"); - assert.isFalse(ArrayBuffer.isView(b), "%TypedArray%.from.call(Array, objectWithLengthProperty) is not a TypedArray (ArrayBuffer.isView)"); - assert.areEqual([0,1,2,undefined,undefined], b, "%TypedArray%.from.call(Array, objectWithLengthProperty) has missing values set to undefined"); + var b = fromFnc.call(Float64Array, a); + assert.areEqual('object', typeof b, "%TypedArray%.from.call(Float64Array, objectWithLengthProperty) returns an object"); + assert.areEqual(5, b.length, "%TypedArray%.from.call(Float64Array, objectWithLengthProperty) returns a new typed array with length = a.length"); + assert.isTrue(ArrayBuffer.isView(b) && b instanceof Float64Array, "%TypedArray%.from.call(Float64Array, objectWithLengthProperty) is a TypedArray (ArrayBuffer.isView)"); + assert.areEqual([0,1,2,NaN,NaN], b, "%TypedArray%.from.call(Float64Array, objectWithLengthProperty) has missing values set to undefined"); var a = { 0: 0, 1: 1 }; - var b = fromFnc.call(Array, a); - assert.areEqual('object', typeof b, "%TypedArray%.from.call(Array, objectWithLengthNoProperty) returns an object"); - assert.areEqual(0, b.length, "%TypedArray%.from.call(Array, objectWithLengthNoProperty) returns a new array with length = 0"); - assert.isFalse(ArrayBuffer.isView(b), "%TypedArray%.from.call(Array, objectWithLengthNoProperty) is not a TypedArray (ArrayBuffer.isView)"); - assert.areEqual([], b, "%TypedArray%.from.call(Array, objectWithLengthNoProperty) is an empty array"); + var b = fromFnc.call(Float64Array, a); + assert.areEqual('object', typeof b, "%TypedArray%.from.call(Float64Array, objectWithLengthNoProperty) returns an object"); + assert.areEqual(0, b.length, "%TypedArray%.from.call(Float64Array, objectWithLengthNoProperty) returns a new Float64Array with length = 0"); + assert.isTrue(ArrayBuffer.isView(b) && b instanceof Float64Array, "%TypedArray%.from.call(Float64Array, objectWithLengthNoProperty) is a TypedArray (ArrayBuffer.isView)"); + assert.areEqual([], b, "%TypedArray%.from.call(Float64Array, objectWithLengthNoProperty) is an empty array"); assert.throws(function () { fromFnc.call(); }, TypeError, "Calling %TypedArray%.from with no this throws TypeError", "[TypedArray].from: 'this' is not a Function object"); assert.throws(function () { fromFnc.call(undefined); }, TypeError, "Calling %TypedArray%.from with undefined this throws TypeError", "[TypedArray].from: 'this' is not a Function object"); @@ -523,7 +523,7 @@ var tests = [ assert.throws(function () { Uint8Array.from({}, null); }, TypeError, "Calling %TypedArray%.from with non-object mapFn argument throws TypeError", "[TypedArray].from: argument is not a Function object"); assert.throws(function () { Uint8Array.from({}, 'string'); }, TypeError, "Calling %TypedArray%.from with non-object mapFn argument throws TypeError", "[TypedArray].from: argument is not a Function object"); assert.throws(function () { Uint8Array.from({}, {}); }, TypeError, "Calling %TypedArray%.from with non-function mapFn argument throws TypeError", "[TypedArray].from: argument is not a Function object"); - assert.throws(function () { fromFnc.call(String, [0,1,2,3]); }, TypeError, "Calling %TypedArray%.from with no this throws TypeError", "Cannot create property for a non-extensible object"); + assert.throws(function () { fromFnc.call(String, [0,1,2,3]); }, TypeError, "Calling %TypedArray%.from with no this throws TypeError", "'this' is not a typed array object"); } }, { @@ -573,21 +573,19 @@ var tests = [ CollectGarbage(); return { done: this.i == 10, - value: { - myi: this.i++ - } + value: this.i++ }; } }; } }; - var b = fromFnc.call(Array, objectWithIterator); - assert.areEqual(10, b.length, "%TypedArray%.from.call(Array, objectWithIterator) returns a new Array with length = objectWithIterator.length"); + var b = fromFnc.call(Float64Array, objectWithIterator); + assert.areEqual(10, b.length, "%TypedArray%.from.call(Float64Array, objectWithIterator) returns a new Float64Array with length = objectWithIterator.length"); for (var i = 0; i < b.length; i++) { assert.isTrue(b[i] !== undefined, "Object at index " + i + " is not undefined"); - assert.areEqual('object', typeof b[i], "Object at index " + i + " is an object"); - assert.areEqual(i, b[i].myi, "Object at index " + i + " has correct value"); + assert.areEqual('number', typeof b[i], "Object at index " + i + " is a number"); + assert.areEqual(i, b[i], "Object at index " + i + " has correct value"); } } }, @@ -837,25 +835,6 @@ var tests = [ assert.areEqual(5, u.byteLength, "Uint8ClampedArray.of(0, -1, 2, 300, 4) returns a TypedArray (with correct byteLength)"); assert.areEqual([0,0,2,255,4], u, "Uint8ClampedArray.of(0, -1, 2, 300, 4) has the correct values"); - var b = ofFnc.call(Array, 'string', 'other string', 5, { 0: 'string val',length:10 }); - assert.areEqual('object', typeof b, "%TypedArray%.of.call(Array, ...someStringsAndObjects) returns an array"); - assert.areEqual(['string','other string',5,{ 0: 'string val',length:10 }], b, "%TypedArray%.of.call(Array, ...someStringsAndObjects) == ['string','other string',5,{ 0: 'string val',length:10 }]"); - assert.areEqual(4, b.length, "%TypedArray%.of.call(Array, ...someStringsAndObjects).length === 4"); - assert.isFalse(ArrayBuffer.isView(b), "%TypedArray%.of.call(Array, ...someStringsAndObjects) is not a TypedArray"); - - var b = ofFnc.call(String, 0, 1, 2, 3); - assert.areEqual('object', typeof b, "%TypedArray%.of.call(String, 0, 1, 2, 3) returns a string object"); - assert.areEqual(1, b.length, "%TypedArray%.of.call(String, 0, 1, 2, 3) returns a string object with length 1"); - assert.areEqual('4', b.toString(), "%TypedArray%.of.call(String, 0, 1, 2, 3) returns a string object with value == '4'"); - assert.areEqual('4', b[0], "%TypedArray%.of.call(String, 0, 1, 2, 3) returns a string object s. s[0] == '4'"); - assert.areEqual(1, b[1], "%TypedArray%.of.call(String, 0, 1, 2, 3) returns a string object s. s[1] == 1"); - assert.areEqual(2, b[2], "%TypedArray%.of.call(String, 0, 1, 2, 3) returns a string object s. s[2] == 2"); - assert.areEqual(3, b[3], "%TypedArray%.of.call(String, 0, 1, 2, 3) returns a string object s. s[3] == 3"); - - assert.areEqual([], ofFnc.call(Array), "%TypedArray%.of.call(Array) returns empty array"); - assert.areEqual(new String(0), ofFnc.call(String), "%TypedArray%.of.call(String) returns empty string"); - assert.areEqual("0", ofFnc.call(String).toString(), "%TypedArray%.of.call(String) returns empty string"); - var b = Uint8Array.of(); assert.areEqual(0, b.length, "Uint8Array.of() returns empty Uint8Array"); assert.areEqual(0, b.byteLength, "Uint8Array.of() returns empty Uint8Array"); @@ -1020,10 +999,13 @@ var tests = [ // If we set the constructor property of some TypedArray to Array built-in constructor, we should get an array object out. var u = getTypedArray(); u.constructor = Array; + assert.throws(()=>u.map(mappingFn, thisArg), TypeError, 'u.map', "'this' is not a typed array object"); + + u.constructor = Int16Array; var r = u.map(mappingFn, thisArg); assert.areEqual([0,-1,-2,-3,-4,-5,-6,-7,-8,-9], r, "%TypedArrayPrototype%.map called on a TypedArray with 'constructor' property set to Array produces the correct values"); - assert.isFalse(ArrayBuffer.isView(r), "%TypedArrayPrototype%.map called on a TypedArray with 'constructor' property set to Array produces a normal array"); + assert.isTrue(ArrayBuffer.isView(r) && r instanceof Int16Array, "%TypedArrayPrototype%.map called on a TypedArray with 'constructor' property set to a different TypedArray produces a typed array"); // %TypedArray%.prototype.map loads the constructor property from the this parameter and uses that to construct the return value. // If we set the constructor property of some TypedArray to a non-constructor, it should throw. @@ -1675,12 +1657,12 @@ var tests = [ assert.areEqual(10, counter, "%TypedArrayPrototype%.filter calls the callback function the correct number of times"); var u = getTypedArray(10); - u.constructor = Array; + u.constructor = Int16Array; counter = 0; var res = filter.call(u, selectOddNumbers, thisArg); assert.areEqual([1,3,5,7,9], res, "%TypedArrayPrototype%.filter returns a new array with the right values"); - assert.isFalse(ArrayBuffer.isView(res), "%TypedArrayPrototype%.filter returns a normal array if the TypedArray constructor property is changed"); - assert.areEqual(undefined, res[Symbol.toStringTag], "%TypedArrayPrototype%.filter return value doesn't have @@toStringTag value"); + assert.isTrue(ArrayBuffer.isView(res) && res instanceof Int16Array, "%TypedArrayPrototype%.filter returns a typed array if the TypedArray constructor property is changed to a different typed array"); + assert.areEqual("Int16Array", res[Symbol.toStringTag], "%TypedArrayPrototype%.filter return value doesn't have @@toStringTag value"); assert.areEqual(10, counter, "%TypedArrayPrototype%.filter calls the callback function the correct number of times"); u.constructor = Math.sin; @@ -2486,20 +2468,6 @@ var tests = [ assert.areEqual([0,1,2,3,4,5,6,7,8,9], arr.subarray(), "Subarray with no begin or end offsets uses 0 and length as respective default values"); } }, - { - name: "%TypedArray%.prototype.subarray uses the constructor property of the this parameter to construct the return object", - body: function() { - var arr = new Uint8Array(10); - arr.constructor = Array; - - var o = arr.subarray(5, 7); - - assert.isTrue(Array.isArray(o), "%TypedArray%.prototype.subarray constructs return object using constructor property - returns an array instance from Array"); - assert.areEqual(arr.buffer, o[0], "%TypedArray%.prototype.subarray calls constructor with the first argument set to the ArrayBuffer of the this parameter"); - assert.areEqual(5, o[1], "%TypedArray%.prototype.subarray calls constructor with the second argument set to the byte offset of the begin argument"); - assert.areEqual(2, o[2], "%TypedArray%.prototype.subarray calls constructor with the third argument set to the length of the subarray"); - } - }, { name: "%TypedArray%.prototype.subarray tests on constructor access through [@@species] - special cases", body: function() {
test/typedarray/typedarray_bugfixes.js+41 −0 modified@@ -20,6 +20,47 @@ var tests = [ assert.areEqual("undefined", typeof new Float64Array()[NaN & 0XF], "TypeofElem should return 'undefined' for out-of-range situation in Float64Array"); } }, + { + name: "OS7115643: TypedArray created through user constructor with insufficient length", + body: function () { + var test = function(TypedArrayCtor) { + class A extends TypedArrayCtor { + static get [Symbol.species]() { return function() { return new TypedArrayCtor(1); }; }; + } + + class B extends TypedArrayCtor { + static get [Symbol.species]() { return function() { return new Array(1); }; }; + } + + var a = new A(1000); + assert.throws(()=>a.map(()=>0), TypeError, TypedArrayCtor.name+'.prototype.map', 'Invalid offset/length when creating typed array'); + assert.throws(()=>a.slice(), TypeError, TypedArrayCtor.name+'.prototype.slice', 'Invalid offset/length when creating typed array'); + assert.doesNotThrow(()=>a.subarray(), TypedArrayCtor.name+'.prototype.subarray', 'Calling subarray should not throw because there\'s no length check'); + assert.throws(()=>a.filter(()=>true), TypeError, TypedArrayCtor.name+'.prototype.filter', 'Invalid offset/length when creating typed array'); + + var b = new B(1000); + assert.throws(()=>b.map(()=>0), TypeError, TypedArrayCtor.name+'.prototype.map', "'this' is not a typed array object"); + assert.throws(()=>b.slice(), TypeError, TypedArrayCtor.name+'.prototype.slice', "'this' is not a typed array object"); + assert.throws(()=>b.subarray(), TypeError, TypedArrayCtor.name+'.prototype.subarray', "'this' is not a typed array object"); + assert.throws(()=>b.filter(()=>true), TypeError, TypedArrayCtor.name+'.prototype.filter', "'this' is not a typed array object"); + + var ctor = function() { return new TypedArrayCtor(1); } + assert.throws(()=>TypedArrayCtor.from.apply(ctor,['123']), TypeError, TypedArrayCtor.name+'.from(iterable)', 'Invalid offset/length when creating typed array'); + assert.throws(()=>TypedArrayCtor.from.apply(ctor,[{"0":1,"1":2,"2":3,"length":3}]), TypeError, TypedArrayCtor.name+'.from(non-iterable)', 'Invalid offset/length when creating typed array'); + assert.throws(()=>TypedArrayCtor.of.apply(ctor,[1,2,3]), TypeError, TypedArrayCtor.name+'.of', 'Invalid offset/length when creating typed array'); + }; + + test(Int8Array); + test(Uint8Array); + test(Uint8ClampedArray); + test(Int16Array); + test(Uint16Array); + test(Int32Array); + test(Uint32Array); + test(Float32Array); + test(Float64Array); + } + }, ]; testRunner.runTests(tests, { verbose: WScript.Arguments[0] != "summary" });
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
8- github.com/advisories/GHSA-vfjw-crcq-q92vghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2016-3199ghsaADVISORY
- www.zerodayinitiative.com/advisories/ZDI-16-367nvdWEB
- www.zerodayinitiative.com/advisories/ZDI-16-368nvdWEB
- docs.microsoft.com/en-us/security-updates/securitybulletins/2016/ms16-068nvdWEB
- github.com/chakra-core/ChakraCore/commit/bcd950efee487bdfd73cd1282de4e02e82e62629ghsaWEB
- web.archive.org/web/20211129115034/http://www.securitytracker.com/id/1036099ghsaWEB
- www.securitytracker.com/id/1036099nvd
News mentions
0No linked articles in our index yet.