CVE-2020-36620: Uncontrolled Resource Consumption (CWE-400)
value: A vulnerability was found in Brondahl EnumStringValues up to 4.0.0. It has been declared as problematic. This vulnerability affects the function GetStringValuesWithPreferences_Uncache of the file EnumStringValues/EnumExtensions.cs. The manipulation leads to resource consumption. Upgrading to version 4.0.1 is able to address this issue. The name of the patch is c0fc7806beb24883cc2f9543ebc50c0820297307. It is recommended to upgrade the affected component. VDB-216466 is the identifier assigned to this vulnerability.
CWE description: The product does not properly control the allocation and maintenance of a limited resource, thereby enabling an actor to influence the amount of resources consumed, eventually leading to the exhaustion of available resources.
CVSS v3 base score: 7.5
Published: 2022-12-21T19:15Z
Repository: https://github.com/Brondahl/EnumStringValues
Language: C#
Files changed: EnumStringValues/EnumExtensions.cs
Commit date: 2020-01-02 11:29:55 +0000
Commit message: Protect against DOS attacks made possible by parsing random invalid enum strings

Diff: diff --git a/EnumStringValues/EnumExtensions.cs b/EnumStringValues/EnumExtensions.cs
index 19f4c03..f3f7562 100644
--- a/EnumStringValues/EnumExtensions.cs
+++ b/EnumStringValues/EnumExtensions.cs
@@ -267,19 +267,16 @@ namespace EnumStringValues
     /// </remarks>
     private static bool TryParseStringValueToEnum_ViaCache<TEnumType>(string lowerStringValue, out TEnumType parsedValue) where TEnumType : System.Enum
     {
       var enumTypeObject = typeof(TEnumType);
 
-      var typeAppropriateDictionary = parsedEnumStringsDictionaryByType.GetOrAdd(enumTypeObject, (x) => new ConcurrentDictionary<string, Enum>());
+      var typeAppropriateDictionary = parsedEnumStringsDictionaryByType.GetOrAdd(
+        enumTypeObject, 
+        (x) => BuildCacheDictionaryForParseStringValue<TEnumType>()
+      );
 
-      var cachedValue = typeAppropriateDictionary.GetOrAdd(lowerStringValue, (str) =>
-      {
-        var parseSucceededForDictionary = TryParseStringValueToEnum_Uncached<TEnumType>(lowerStringValue, out var parsedValueForDictionary);
-        return parseSucceededForDictionary ? (Enum) parsedValueForDictionary : null;
-      });
-
-      if (cachedValue != null)
+      if (typeAppropriateDictionary.TryGetValue(lowerStringValue, out var cachedValue))
       {
         parsedValue = (TEnumType)cachedValue;
         return true;
       }
       else
@@ -290,10 +287,29 @@ namespace EnumStringValues
     }
 
     /// <summary> Cache for <see cref="TryParseStringValueToEnum{TEnumType}"/> </summary>
     private static ConcurrentDictionary<Type, ConcurrentDictionary<string, Enum>> parsedEnumStringsDictionaryByType;
 
+
+    private static ConcurrentDictionary<string, Enum> BuildCacheDictionaryForParseStringValue<TEnumType>() where TEnumType : System.Enum
+    {
+      var dict = new ConcurrentDictionary<string, Enum>();
+
+      foreach (var enumValue in EnumerateValues<TEnumType>())
+      {
+        foreach (var enumString in GetStringValues<TEnumType>(enumValue))
+        {
+            // Add to the dictionary, just overwriting if the string is already present.
+            // This overwrite is legitimate, because we've declared parsing a duplicate string definition to be `undefined behaviour`.
+            dict.AddOrUpdate(enumString.ToLower(), enumValue, ((repeatedString, previousEnumValue) => enumValue));
+        }
+      }
+
+      return dict;
+    }
+
+
     private static bool TryParseStringValueToEnum_Uncached<TEnumType>(this string lowerStringValue, out TEnumType parsedValue) where TEnumType : System.Enum
     {
       foreach (var enumValue in EnumerateValues<TEnumType>())
       {
         var enumStrings = GetStringValues<TEnumType>(enumValue).Select(text => text.ToLower());

Vulnerable code:       var typeAppropriateDictionary = parsedEnumStringsDictionaryByType.GetOrAdd(enumTypeObject, (x) => new ConcurrentDictionary<string, Enum>());
      var cachedValue = typeAppropriateDictionary.GetOrAdd(lowerStringValue, (str) =>
      {
        var parseSucceededForDictionary = TryParseStringValueToEnum_Uncached<TEnumType>(lowerStringValue, out var parsedValueForDictionary);
        return parseSucceededForDictionary ? (Enum) parsedValueForDictionary : null;
      });

      if (cachedValue != null)
Fixed code:       var typeAppropriateDictionary = parsedEnumStringsDictionaryByType.GetOrAdd(
        enumTypeObject, 
        (x) => BuildCacheDictionaryForParseStringValue<TEnumType>()
      );
      if (typeAppropriateDictionary.TryGetValue(lowerStringValue, out var cachedValue))

    private static ConcurrentDictionary<string, Enum> BuildCacheDictionaryForParseStringValue<TEnumType>() where TEnumType : System.Enum
    {
      var dict = new ConcurrentDictionary<string, Enum>();

      foreach (var enumValue in EnumerateValues<TEnumType>())
      {
        foreach (var enumString in GetStringValues<TEnumType>(enumValue))
        {
            // Add to the dictionary, just overwriting if the string is already present.
            // This overwrite is legitimate, because we've declared parsing a duplicate string definition to be `undefined behaviour`.
            dict.AddOrUpdate(enumString.ToLower(), enumValue, ((repeatedString, previousEnumValue) => enumValue));
        }
      }

      return dict;
    }