astrid-runtime/astrid · critical

OS CSPRNG unavailable while generating invite suffix

Error message

OS CSPRNG unavailable while generating invite suffix

What it means

Panic from `SysRng.try_fill_bytes(&mut bytes).expect("OS CSPRNG unavailable while generating invite suffix")` in `random_suffix` (crates/astrid-kernel/src/kernel_router/admin/invite_handlers.rs:481). It draws 4 random bytes for a hex invite suffix from the OS CSPRNG and deliberately panics if that source is unavailable, refusing insecure fallback.

Solutions

  1. Fix the environment: allow getrandom(2) in the sandbox profile or mount /dev/urandom in the container.
  2. Start an entropy maintenance service (rngd, haveged) if running on hardware/VMs with slow entropy init.
  3. Have random_suffix return Result and map failure to an admin error response instead of panicking the handler thread.
  4. Check kernel logs (dmesg) for crng init failures to confirm the diagnosis.

Example fix

// before
SysRng.try_fill_bytes(&mut bytes).expect("OS CSPRNG unavailable while generating invite suffix");
// after
let suffix = SysRng.try_fill_bytes(&mut bytes)
    .ok()
    .map(|_| hex::encode(bytes))
    .ok_or_else(|| AdminError::RngUnavailable)?;
Defensive patterns

Strategy: try-catch

Validate before calling

use rand::{TryRng, rngs::SysRng};
fn rng_available() -> bool {
    let mut b = [0u8; 1];
    SysRng.try_fill_bytes(&mut b).is_ok()
}

Try / catch

let suffix = std::panic::catch_unwind(random_suffix)
    .map_err(|_| AdminError::RngUnavailable)?; // return err_bad_input-style error instead of panicking

Prevention

When it happens

Trigger: Any admin invite-handler request that calls `random_suffix()` while the OS entropy source fails: seccomp-filtered getrandom, missing /dev/urandom, sandboxed processes, or pre-entropy-early-boot environments.

Common situations: Same environmental causes as token generation — hardened containers, restricted service sandboxes (systemd RestrictNamespaces/seccomp profiles), minimal VM images without entropy daemons.

Related errors


AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09). Data as JSON: /api/errors/6a5c0e2fcacdbf1a. Report an issue: GitHub.

Appendix: source

Thrown at crates/astrid-kernel/src/kernel_router/admin/invite_handlers.rs:481

            out.push(ch.to_ascii_lowercase());
            last_was_dash = false;
        } else if !last_was_dash && !out.is_empty() {
            out.push('-');
            last_was_dash = true;
        }
    }
    while out.ends_with('-') {
        out.pop();
    }
    out
}

fn random_suffix() -> String {
    use rand::{TryRng, rngs::SysRng};
    let mut bytes = [0u8; 4];
    SysRng
        .try_fill_bytes(&mut bytes)
        .expect("OS CSPRNG unavailable while generating invite suffix");
    hex::encode(bytes)
}

fn err_bad_input(msg: String) -> AdminResponseBody {
    warn!(error = %msg, "invite request rejected: bad input");
    AdminResponseBody::Error(msg)
}

fn err_internal(msg: String) -> AdminResponseBody {
    warn!(error = %msg, "invite request failed: internal error");
    AdminResponseBody::Error(msg)
}

fn err_unauthorized(msg: String) -> AdminResponseBody {
    warn!(security_event = true, error = %msg, "invite request denied");
    AdminResponseBody::Error(msg)
}

View on GitHub (pinned to affd8760f4)