diff --git a/.jules/sentinel.md b/.jules/sentinel.md new file mode 100644 index 0000000000..db2769425d --- /dev/null +++ b/.jules/sentinel.md @@ -0,0 +1,4 @@ +## 2024-05-24 - [Insecure Random Number Generation] +**Vulnerability:** Weak random number generation using `random.choices` for passwords and unique identifiers (e.g. root SSH password, user IDs, session IDs). +**Learning:** `random.choices` is not cryptographically secure and predictable. It should never be used for security-sensitive operations. +**Prevention:** Always use the `secrets` module (e.g. `secrets.choice`) for generating cryptographic or security-sensitive identifiers. 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)