From 701ed41be1507c8a00edb2db865fe10159f4638f Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Mon, 18 May 2026 09:19:14 +0000 Subject: [PATCH] Replace random.choices with secrets.choice for secure id generation Co-authored-by: thirdeyenation <133812267+thirdeyenation@users.noreply.github.com> --- .jules/sentinel.md | 4 ++++ agent.py | 4 ++-- helpers/guids.py | 4 ++-- prepare.py | 3 ++- 4 files changed, 10 insertions(+), 5 deletions(-) create mode 100644 .jules/sentinel.md 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)