{"record":{"id":"070ad5b7f42b6881","repo":"astrid-runtime/astrid","slug":"os-csprng-unavailable-while-generating-invite-toke","errorCode":null,"errorMessage":"OS CSPRNG unavailable while generating invite token","messagePattern":"OS CSPRNG unavailable while generating invite token","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"crates/astrid-kernel/src/invite/mod.rs","lineNumber":675,"sourceCode":"struct PersistedFile {\n    #[serde(default)]\n    schema_version: u32,\n    #[serde(default)]\n    invite: Vec<Invite>,\n}\n\n/// Generate a typed token with a random URL-safe-base64 secret. Uses the OS CSPRNG.\n///\n/// # Panics\n///\n/// Panics if the OS CSPRNG is unavailable.\n#[must_use]\npub fn generate_token() -> String {\n    use rand::{TryRng, rngs::SysRng};\n    let mut bytes = [0u8; TOKEN_RAW_LEN];\n    SysRng\n        .try_fill_bytes(&mut bytes)\n        .expect(\"OS CSPRNG unavailable while generating invite token\");\n    format!(\n        \"{TOKEN_PREFIX}{}\",\n        base64::engine::general_purpose::URL_SAFE_NO_PAD.encode(bytes)\n    )\n}\n\n/// Derive a token identifier for storage and lookup.\n#[must_use]\npub fn hash_token(token: &str) -> String {\n    IdentifierHash::derive(TOKEN_HASH_CONTEXT, token.as_bytes()).to_prefixed_hex()\n}\n\n/// Constant-time hash comparison. Both inputs must be `blake3:<hex>`\n/// identifiers. Returns `false` on any length mismatch\n/// without leaking the position via short-circuit.\n#[must_use]\npub fn ct_hash_eq(a: &str, b: &str) -> bool {\n    if a.len() != b.len() {","sourceCodeStart":657,"sourceCodeEnd":693,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-kernel/src/invite/mod.rs#L657-L693","documentation":"Panic from `SysRng.try_fill_bytes(&mut bytes).expect(\"OS CSPRNG unavailable while generating invite token\")` in `generate_token` (crates/astrid-kernel/src/invite/mod.rs:675). The library refuses to generate an invite token from anything but the OS cryptographically secure RNG (rand::rngs::SysRng); if the operating system's entropy source (/dev/urandom, getrandom) is unavailable, it panics rather than fall back to a weak source.","triggerScenarios":"Calling `generate_token()` on a system where the OS CSPRNG fails: exhausted/fileless entropy setups, containers without /dev/urandom, seccomp/sandbox rules blocking getrandom(2), or extremely early boot before entropy initialization.","commonSituations":"Hardened containers with restricted syscalls, chroot/jail environments missing device nodes, custom Linux builds without getrandom, or VM snapshots resumed with RNG misconfiguration.","solutions":["Restore OS entropy access: ensure /dev/urandom exists and getrandom(2) is permitted by seccomp/AppArmor/sandbox policy.","If running in a container, add the device and adjust the syscall allowlist (e.g. docker run with proper /dev mounts).","Retry at process start after entropy is initialized (wait for rngd / kernel crng ready).","Replace expect with error propagation (try_fill_bytes returns Result) so callers can degrade gracefully instead of panicking."],"exampleFix":"// before\nSysRng.try_fill_bytes(&mut bytes).expect(\"OS CSPRNG unavailable while generating invite token\");\n// after\nSysRng.try_fill_bytes(&mut bytes)\n    .map_err(|e| InviteError::RngUnavailable(e))?;","handlingStrategy":"try-catch","validationCode":"// preflight: verify OS CSPRNG works before generating tokens\nuse rand::{TryRng, rngs::SysRng};\nlet mut probe = [0u8; 1];\nlet rng_ok = SysRng.try_fill_bytes(&mut probe).is_ok();","typeGuard":null,"tryCatchPattern":"// wrap token generation so panics don't take down the request\nlet token = std::panic::catch_unwind(generate_token)\n    .map_err(|_| InviteError::RngUnavailable)?;","preventionTips":["Smoke-test the RNG at service startup and fail fast with a clear message.","Ensure containers allow getrandom(2) and expose /dev/urandom.","Avoid generating tokens before kernel crng initialization on early-boot systems.","Prefer a fallible generate_token API over expect in library code."],"tags":["random","security","entropy","panic","kernel"],"backgroundTag":"missing-entropy-source","analyzedSha":"affd8760f44190dbdfbec23403f4c4b642c33112","analyzedAt":"2026-09-09T21:28:12.402Z","contentChangedAt":"2026-09-09T21:28:12.402Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}