{"record":{"id":"6a5e8a8819444e68","repo":"paragonie/random_compat","slug":"environment-misconfiguration-dev-urandom-cannot-be-read","errorCode":null,"errorMessage":"Environment misconfiguration: /dev/urandom cannot be read.","messagePattern":"Environment misconfiguration: /dev/urandom cannot be read\\.","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"critical","filePath":"lib/random_bytes_dev_urandom.php","lineNumber":69,"sourceCode":"        static $fp = null;\n\n        /**\n         * This block should only be run once\n         */\n        if (empty($fp)) {\n            /**\n             * We don't want to ever read C:\\dev\\random, only /dev/urandom on\n             * Unix-like operating systems. While we guard against this\n             * condition in random.php, it doesn't hurt to be defensive in depth\n             * here.\n             *\n             * To that end, we only try to open /dev/urandom if we're on a Unix-\n             * like operating system (which means the directory separator is set\n             * to \"/\" not \"\\\".\n             */\n            if (DIRECTORY_SEPARATOR === '/') {\n                if (!is_readable('/dev/urandom')) {\n                    throw new Exception(\n                        'Environment misconfiguration: ' .\n                        '/dev/urandom cannot be read.'\n                    );\n                }\n                /**\n                 * We use /dev/urandom if it is a char device.\n                 * We never fall back to /dev/random\n                 */\n                /** @var resource|bool $fp */\n                $fp = fopen('/dev/urandom', 'rb');\n                if (is_resource($fp)) {\n                    /** @var array<string, int> $st */\n                    $st = fstat($fp);\n                    if (($st['mode'] & 0170000) !== 020000) {\n                        fclose($fp);\n                        $fp = false;\n                    }\n                }","sourceCodeStart":51,"sourceCodeEnd":87,"githubUrl":"https://github.com/paragonie/random_compat/blob/b5d188cc9d5e02f94d2c41da23093f1ef557c5b1/lib/random_bytes_dev_urandom.php#L51-L87","documentation":"random_compat's /dev/urandom backend only opens /dev/urandom when running on a Unix-like OS (DIRECTORY_SEPARATOR === '/'). If is_readable('/dev/urandom') returns false, the library throws because it cannot access the system CSPRNG and must not fall back to weak randomness. This indicates a broken or hostile environment rather than bad arguments.","triggerScenarios":"Calling random_bytes() on a Unix-like system where /dev/urandom does not exist, is not readable by the PHP process (permissions, chroot/jail without /dev, hardened open_basedir), or the filesystem lacks the device node (some containers/minimal images).","commonSituations":"Docker/alpine or minimal chroot images without /dev mounted or without the urandom device; hosting environments using open_basedir restricting access to /dev; running PHP as a user without read permission on /dev/urandom; misconfigured chroot for PHP-FPM.","solutions":["Ensure /dev/urandom exists and is readable by the PHP user; in containers mount dev (e.g. add /dev/urandom device or run with proper device cgroup).","Check and fix open_basedir restrictions: add /dev/urandom to open_basedir in php.ini.","Fix filesystem permissions on /dev/urandom (typically 0666 root:root) or the chroot so the device node is present.","Upgrade PHP to >= 7.0 for native random_bytes() and verify random_compat still selects a working backend (check which file was loaded)."],"exampleFix":"// before (fails in restricted env)\n$token = random_bytes(32);\n// after\nif (!is_readable('/dev/urandom')) {\n    error_log('CSPRNG unavailable: /dev/urandom not readable; check open_basedir/chroot/container /dev mount');\n}\n$token = random_bytes(32);","handlingStrategy":"try-catch","validationCode":"if (DIRECTORY_SEPARATOR === '/' && !is_readable('/dev/urandom')) {\n    throw new RuntimeException(\"Environment misconfiguration: /dev/urandom unavailable\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    $bytes = random_bytes(32);\n} catch (Exception $e) {\n    if (strpos($e->getMessage(), '/dev/urandom') !== false) {\n        // fix env (mount /dev, open_basedir, permissions) — do not use weak RNG\n        throw new RuntimeException('CSPRNG environment misconfiguration', 0, $e);\n    }\n    throw $e;\n}","preventionTips":["Ensure containers/chroots expose /dev/urandom (mount devtmpfs or add the device node).","Keep /dev/urandom out of open_basedir restrictions or explicitly allow it.","Verify is_readable('/dev/urandom') as a health check at application boot.","Run PHP >= 7.0 with a properly provisioned OS so native random_bytes() works."],"tags":["php","environment","urandom","entropy","permissions"],"backgroundTag":"environment-misconfiguration","analyzedSha":"b5d188cc9d5e02f94d2c41da23093f1ef557c5b1","analyzedAt":"2026-09-13T16:12:09.755Z","contentChangedAt":"2026-09-13T16:12:09.755Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}