{"record":{"id":"230232e1c840b98b","repo":"elastic/elasticsearch","slug":"too-large-literallen","errorCode":null,"errorMessage":"Too large literalLen","messagePattern":"Too large literalLen","errorType":"exception","errorClass":"LZ4Exception","httpStatus":null,"severity":"error","filePath":"libs/lz4/src/main/java/org/elasticsearch/lz4/ESLZ4Decompressor.java","lineNumber":88,"sourceCode":"\n        int sOff = srcOff;\n        int dOff = destOff;\n\n        while (true) {\n            if (sOff >= srcEnd) {\n                throw new LZ4Exception(\"Malformed input at \" + sOff);\n            }\n            final int token = SafeUtils.readByte(src, sOff) & 0xFF;\n            ++sOff;\n\n            // literals\n            int literalLen = token >>> ML_BITS;\n            if (literalLen == RUN_MASK) {\n                byte len = (byte) 0xFF;\n                while (sOff < srcEnd && (len = SafeUtils.readByte(src, sOff++)) == (byte) 0xFF) {\n                    literalLen += 0xFF;\n                    if (literalLen < 0) {\n                        throw new LZ4Exception(\"Too large literalLen\");\n                    }\n                }\n                literalLen += len & 0xFF;\n            }\n\n            final int literalCopyEnd = dOff + literalLen;\n            // Check for overflow\n            if (literalCopyEnd < dOff) {\n                throw new LZ4Exception(\"Too large literalLen\");\n            }\n\n            if (notEnoughSpace(destEnd - literalCopyEnd, COPY_LENGTH) || notEnoughSpace(srcEnd - sOff, COPY_LENGTH + literalLen)) {\n\n                if (literalCopyEnd != destEnd) {\n                    throw new LZ4Exception(\"Malformed input at \" + sOff);\n                } else if (notEnoughSpace(srcEnd - sOff, literalLen)) {\n                    throw new LZ4Exception(\"Malformed input at \" + sOff);\n","sourceCodeStart":70,"sourceCodeEnd":106,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/libs/lz4/src/main/java/org/elasticsearch/lz4/ESLZ4Decompressor.java#L70-L106","documentation":"When the literal-length nibble equals RUN_MASK (15), the decoder reads a chain of 0xFF extension bytes, adding 255 each time. If the accumulated literalLen overflows int (goes negative), the declared literal length exceeds any plausible buffer and the stream is malformed. This bounds the variable-length literal encoding.","triggerScenarios":"Decompressing an LZ4 block whose literal-length extension bytes sum beyond Integer.MAX_VALUE, i.e. more than ~8.4 million 0xFF bytes precede the terminating length byte. Indicates crafted or severely corrupt input.","commonSituations":"Fuzzed or adversarial LZ4 input. Memory corruption that overwrites length bytes with 0xFF. A buffer from an incompatible LZ4 implementation.","solutions":["Treat the input as corrupt; do not trust the source block.","Restore the data from a known-good replica or snapshot.","If generating the input programmatically, ensure the literal-length encoding matches the LZ4 spec."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// No safe pre-check; overflow is detected during decode. Bound the declared destLen against srcLen as a heuristic.\nif (destLen > srcLen * 255L) { // literals can't expand more than ~255x\n    throw new IllegalArgumentException(\"Implausible LZ4 destLen for given srcLen\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    ESLZ4Decompressor.INSTANCE.decompress(src, srcOff, dest, destOff, destLen);\n} catch (LZ4Exception e) {\n    // literal-length overflow => corrupt or adversarial input\n    markCorruptAndRecover();\n}","preventionTips":["Reject implausible destLen/srcLen ratios before decompression.","Treat any LZ4Exception during decode as corrupt input.","Do not attempt to repair corrupt blocks in place; recover from replicas."],"tags":["lz4","decompression","corruption","overflow","literal-length"],"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-12T12:17:08.281Z"}