{"record":{"id":"6c62357005c82d16","repo":"atuinsh/atuin","slug":"failed-to-generate-random-bytes","errorCode":null,"errorMessage":"Failed to generate random bytes!","messagePattern":"Failed to generate random bytes!","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/atuin-common/src/utils.rs","lineNumber":17,"sourceCode":"use std::env;\nuse std::ffi::OsString;\nuse std::path::{Path, PathBuf};\n\nuse eyre::{Result, eyre};\n\nuse base64::prelude::{BASE64_URL_SAFE_NO_PAD, Engine};\nuse getrandom::fill;\nuse uuid::Uuid;\n\n/// Generate N random bytes, using a cryptographically secure source\npub fn crypto_random_bytes<const N: usize>() -> [u8; N] {\n    // rand say they are in principle safe for crypto purposes, but that it is perhaps a better\n    // idea to use getrandom for things such as passwords.\n    let mut ret = [0u8; N];\n\n    fill(&mut ret).expect(\"Failed to generate random bytes!\");\n\n    ret\n}\n\n/// Generate N random bytes using a cryptographically secure source, return encoded as a string\npub fn crypto_random_string<const N: usize>() -> String {\n    let bytes = crypto_random_bytes::<N>();\n\n    // We only use this to create a random string, and won't be reversing it to find the original\n    // data - no padding is OK there. It may be in URLs.\n    BASE64_URL_SAFE_NO_PAD.encode(bytes)\n}\n\npub fn uuid_v7() -> Uuid {\n    Uuid::now_v7()\n}\n\npub fn uuid_v4() -> String {","sourceCodeStart":1,"sourceCodeEnd":35,"githubUrl":"https://github.com/atuinsh/atuin/blob/202f6ad98ee0da165c35cdb2afbc5b13d6ab81a1/crates/atuin-common/src/utils.rs#L1-L35","documentation":"crypto_random_bytes() fills a buffer via getrandom::fill, which draws from the OS CSPRNG (getrandom(2) on Linux, getentropy on macOS/BSD, BCryptGenRandom on Windows). fill returns Err only when the operating system cannot provide secure randomness at all; atuin treats that as unrecoverable and panics. This helper backs key and session-id generation (e.g. share spawn ids, encryption key material paths), so the failure is fatal by design.","triggerScenarios":"Calling crypto_random_bytes/crypto_random_string where the OS RNG is unreachable: a seccomp or container policy blocking the getrandom/getentropy syscall, a kernel older than Linux 3.17 with no usable /dev/urandom, extremely early boot before the kernel CRNG is seeded, or a stripped container image missing /dev/urandom.","commonSituations":"Custom Docker seccomp profiles, gVisor/Kata configurations, or AppArmor rules denying getrandom(2); ancient kernels or minimal embedded targets; hardened images mounting an empty /dev.","solutions":["Allow the getrandom (and where relevant getentropy) syscalls in the container/seccomp policy","Use a Linux 3.17+ kernel or a modern base image so the OS RNG is available","Ensure /dev/urandom exists and is readable in minimal containers","For entropy-starved VMs, add an entropy source (virtio-rng) or delay atuin startup until the CRNG is seeded"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"fn os_rng_available() -> bool {\n    getrandom::fill(&mut [0u8; 8]).is_ok()\n}\n\nif !os_rng_available() {\n    eprintln!(\"OS secure RNG unavailable; fix the sandbox/kernel before using atuin\");\n    std::process::exit(1);\n}","typeGuard":null,"tryCatchPattern":"match std::panic::catch_unwind(|| atuin_common::utils::crypto_random_string::<32>()) {\n    Ok(token) => token,\n    Err(_) => {\n        // RNG failure is fatal; never fall back to weak randomness\n        eprintln!(\"OS RNG unavailable (blocked getrandom? old kernel? unseeded CRNG?)\");\n        std::process::exit(1);\n    }\n}","preventionTips":["Audit seccomp/AppArmor/gVisor policies for getrandom/getentropy before deploying atuin into sandboxes","Smoke-test one crypto_random_string call at startup so failures surface with a clear message","Never catch this panic and substitute a non-CSPRNG source"],"tags":["rust","getrandom","entropy","crypto","panic","seccomp"],"backgroundTag":"entropy-source-unavailable","analyzedSha":"202f6ad98ee0da165c35cdb2afbc5b13d6ab81a1","analyzedAt":"2026-08-16T19:30:24.731Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}