diff --git a/.jules/sentinel.md b/.jules/sentinel.md new file mode 100644 index 0000000000..2a948800c3 --- /dev/null +++ b/.jules/sentinel.md @@ -0,0 +1,4 @@ +## 2024-06-25 - Weak random number generation +**Vulnerability:** Weak random number generation using `random.choices` for generating passwords and internal identifiers. +**Learning:** `random.choices` is a pseudo-random number generator that is not cryptographically secure, and should not be used in security-sensitive contexts like generating passwords. +**Prevention:** Use `secrets.choice` or `secrets.token_urlsafe` for generating random strings or passwords. diff --git a/agent.py b/agent.py index 267a908077..f29f0d41da 100644 --- a/agent.py +++ b/agent.py @@ -1,4 +1,4 @@ -import asyncio, random, string, threading +import asyncio, random, string, threading, secrets from collections import OrderedDict from dataclasses import dataclass, field @@ -135,7 +135,7 @@ def all(): @staticmethod def generate_id(): def generate_short_id(): - return "".join(random.choices(string.ascii_letters + string.digits, k=8)) + return "".join(secrets.choice(string.ascii_letters + string.digits) for _ in range(8)) while True: short_id = generate_short_id() diff --git a/helpers/guids.py b/helpers/guids.py index f0def4b4c6..41439e4bbe 100644 --- a/helpers/guids.py +++ b/helpers/guids.py @@ -1,4 +1,4 @@ -import random, string +import random, string, secrets def generate_id(length: int = 8) -> str: - return "".join(random.choices(string.ascii_letters + string.digits, k=length)) + return "".join(secrets.choice(string.ascii_letters + string.digits) for _ in range(length)) diff --git a/prepare.py b/prepare.py index a4c4af9c45..ec0fcc714d 100644 --- a/prepare.py +++ b/prepare.py @@ -1,6 +1,7 @@ from helpers import dotenv, runtime, settings import string import random +import secrets import sys from helpers.print_style import PrintStyle @@ -33,7 +34,7 @@ def _retire_legacy_collabora_runtime() -> None: # generate random root password if not set (for SSH) root_pass = dotenv.get_dotenv_value(dotenv.KEY_ROOT_PASSWORD) if not root_pass: - root_pass = "".join(random.choices(string.ascii_letters + string.digits, k=32)) + root_pass = "".join(secrets.choice(string.ascii_letters + string.digits) for _ in range(32)) PrintStyle.standard("Changing root password...") settings.set_root_password(root_pass)