{"record":{"id":"f0068f98342e8067","repo":"ory/kratos","slug":"scrypt-p-d-not-in-1-d","errorCode":null,"errorMessage":"scrypt p=%d not in [1, %d]","messagePattern":"scrypt p=(.+?) not in \\[1, (.+?)\\]","errorType":"validation","errorClass":"ErrHashParametersOutOfBounds","httpStatus":null,"severity":"error","filePath":"hash/hash_limits.go","lineNumber":100,"sourceCode":"\t}\n\tif r == 0 || r > maxScryptR {\n\t\treturn errors.Wrapf(ErrHashParametersOutOfBounds, \"firescrypt r=%d not in [1, %d]\", r, maxScryptR)\n\t}\n\tif p == 0 || p > maxScryptP {\n\t\treturn errors.Wrapf(ErrHashParametersOutOfBounds, \"firescrypt p=%d not in [1, %d]\", p, maxScryptP)\n\t}\n\treturn nil\n}\n\nfunc validateScryptParams(n, r, p uint32) error {\n\tif n == 0 || n > maxScryptN {\n\t\treturn errors.Wrapf(ErrHashParametersOutOfBounds, \"scrypt N=%d not in [1, %d]\", n, maxScryptN)\n\t}\n\tif r == 0 || r > maxScryptR {\n\t\treturn errors.Wrapf(ErrHashParametersOutOfBounds, \"scrypt r=%d not in [1, %d]\", r, maxScryptR)\n\t}\n\tif p == 0 || p > maxScryptP {\n\t\treturn errors.Wrapf(ErrHashParametersOutOfBounds, \"scrypt p=%d not in [1, %d]\", p, maxScryptP)\n\t}\n\treturn nil\n}\n\nfunc validateArgon2Params(memoryKiB uint64, iterations uint32, parallelism uint8) error {\n\tif memoryKiB == 0 || memoryKiB > uint64(maxArgon2MemoryKiB) {\n\t\treturn errors.Wrapf(ErrHashParametersOutOfBounds, \"argon2 m=%d KiB not in [1, %d]\", memoryKiB, maxArgon2MemoryKiB)\n\t}\n\tif iterations == 0 || iterations > maxArgon2Iterations {\n\t\treturn errors.Wrapf(ErrHashParametersOutOfBounds, \"argon2 t=%d not in [1, %d]\", iterations, maxArgon2Iterations)\n\t}\n\tif parallelism == 0 || parallelism > maxArgon2Parallelism {\n\t\treturn errors.Wrapf(ErrHashParametersOutOfBounds, \"argon2 p=%d not in [1, %d]\", parallelism, maxArgon2Parallelism)\n\t}\n\treturn nil\n}\n\nfunc validatePbkdf2Params(iterations uint32) error {","sourceCodeStart":82,"sourceCodeEnd":118,"githubUrl":"https://github.com/ory/kratos/blob/b86338da04a040247a07f46100a86dcfb3875909/hash/hash_limits.go#L82-L118","documentation":"This error means a plain scrypt hash declares a p (parallelization) parameter outside the valid range [1, 10]. p=0 does no work; high p multiplies CPU time linearly because Go's scrypt runs iterations serially, so a crafted hash could make every login attempt burn seconds of CPU. It wraps ErrHashParametersOutOfBounds from validateScryptParams.","triggerScenarios":"decodeScryptHash sees a scrypt hash with p=0 or p>10 (OWASP's highest documented config uses p=10), during import validation or password comparison.","commonSituations":"Migrating from systems tuned with high parallelization; forged hash imports via the admin API; copy-paste mistakes between KDF parameter sets.","solutions":["Verify the p field is in [1, 10] and adjust or regenerate the hash","Re-hash with an OWASP-recommended preset (N=2^17, r=8, p=1)","Use rehash-on-login for users whose hashes legitimately exceed the ceiling"],"exampleFix":"// before (p=24, rejected)\n$scrypt$N=131072$r=8$p=24$...\n// after (p=1, accepted)\n$scrypt$N=131072$r=8$p=1$...","handlingStrategy":"validation","validationCode":"func scryptPOK(p uint32) bool { return p >= 1 && p <= 10 }\n// Or pre-validate the whole hash: hash.ValidateImportedHash(hashed)","typeGuard":null,"tryCatchPattern":"if err := hash.ValidateImportedHash(raw); errors.Is(err, hash.ErrHashParametersOutOfBounds) {\n    return fmt.Errorf(\"scrypt p out of range: %w\", err)\n}","preventionTips":["Keep p=1 (Go's scrypt gains nothing from p>1 since iterations run serially)","Cap p at 10 in upstream hash-generation tooling before export","Validate every imported hash with ValidateImportedHash"],"tags":["hashing","scrypt"],"backgroundTag":"value-out-of-range","analyzedSha":"b86338da04a040247a07f46100a86dcfb3875909","analyzedAt":"2026-09-07T15:58:15.934Z","contentChangedAt":"2026-09-07T15:58:15.934Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}