{"record":{"id":"63a04d39ed3c55a7","repo":"crowdsecurity/crowdsec","slug":"not-enough-entropy-at-random-seed-generation-for-j","errorCode":null,"errorMessage":"not enough entropy at random seed generation for JWT generation","messagePattern":"not enough entropy at random seed generation for JWT generation","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"pkg/apiserver/middlewares/v1/jwt.go","lineNumber":261,"sourceCode":"\nfunc Unauthorized(c *gin.Context, code int, message string) {\n\tc.JSON(code, gin.H{\n\t\t\"code\":    code,\n\t\t\"message\": message,\n\t})\n}\n\nfunc randomSecret() ([]byte, error) {\n\tsize := 64\n\tsecret := make([]byte, size)\n\n\tn, err := rand.Read(secret)\n\tif err != nil {\n\t\treturn nil, errors.New(\"unable to generate a new random seed for JWT generation\")\n\t}\n\n\tif n != size {\n\t\treturn nil, errors.New(\"not enough entropy at random seed generation for JWT generation\")\n\t}\n\n\treturn secret, nil\n}\n\nfunc NewJWT(dbClient *database.Client) (*JWT, error) {\n\t// Get secret from environment variable \"SECRET\"\n\tvar (\n\t\tsecret []byte\n\t\terr    error\n\t)\n\n\t// Please be aware that brute force HS256 is possible.\n\t// PLEASE choose a STRONG secret\n\tsecretString := os.Getenv(\"CS_LAPI_SECRET\")\n\tsecret = []byte(secretString)\n\n\tswitch l := len(secret); {","sourceCodeStart":243,"sourceCodeEnd":279,"githubUrl":"https://github.com/crowdsecurity/crowdsec/blob/909b5157986a2b2c2163300fdaef5ed01289f7d2/pkg/apiserver/middlewares/v1/jwt.go#L243-L279","documentation":"After rand.Read succeeds, randomSecret verifies it filled the whole 64-byte slice; a short read returns \"not enough entropy at random seed generation for JWT generation\". crypto/rand.Read is documented to always fill the buffer or error, so this branch is a defensive invariant check for a non-conforming or interrupted random source.","triggerScenarios":"crypto/rand.Read returns n < 64 without an error — essentially never with the standard Go runtime, but possible with exotic platforms, fuzzing/instrumented builds, or a vendored replaced crypto/rand implementation.","commonSituations":"Custom Go toolchains or WASM/embedded builds with stubbed crypto/rand; test environments that replace the rand reader; effectively never in normal Linux/Windows/macOS deployments.","solutions":["Use the standard Go toolchain and unmodified crypto/rand (check go.mod for crypto/rand replaces)","Set CS_LAPI_SECRET explicitly to bypass randomSecret entirely","If on an exotic platform, provide a working random source to the runtime","Retry startup; a transient short read will normally not recur"],"exampleFix":"// before: relying on runtime entropy on a limited platform\n// after\nexport CS_LAPI_SECRET=$(head -c 48 /dev/urandom | base64 | tr -d '\\n')","handlingStrategy":"retry","validationCode":"// sanity-check the platform's random source before starting the service:\nhead -c 64 /dev/urandom > /dev/null && echo \"entropy ok\"","typeGuard":null,"tryCatchPattern":"jwt, err := NewJWT(dbClient)\nif err != nil {\n    // transient entropy issue: retry once before failing\n    jwt, err = NewJWT(dbClient)\n}\nif err != nil { log.Fatalf(\"cannot start LAPI auth: %v\", err) }","preventionTips":["Avoid vendoring/replacing crypto/rand in builds embedding crowdsec","Set CS_LAPI_SECRET explicitly to bypass randomSecret on unusual platforms","Use the standard Go toolchain and upstream crowdsec binaries"],"tags":["crypto","entropy","startup","jwt"],"backgroundTag":"internal-invariant-violation","analyzedSha":"909b5157986a2b2c2163300fdaef5ed01289f7d2","analyzedAt":"2026-09-06T12:27:26.012Z","contentChangedAt":"2026-09-06T12:27:26.012Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}