{"record":{"id":"05a1a97aff9379da","repo":"Tencent/tinker","slug":"invalid-general-purpose-bit-flag-gpbf","errorCode":null,"errorMessage":"Invalid General Purpose Bit Flag: ${gpbf}","messagePattern":"Invalid General Purpose Bit Flag: (.+?)","errorType":"exception","errorClass":"ZipException","httpStatus":null,"severity":"error","filePath":"third-party/tinker-ziputils/src/main/java/com/tencent/tinker/ziputils/ziputil/TinkerZipEntry.java","lineNumber":144,"sourceCode":"     * at the CDE signature. If the GPBF_UTF8_FLAG is set in the CDE then\n     * UTF-8 is used to decode the string information, otherwise the\n     * defaultCharset is used.\n     *\n     * On exit, \"in\" will be positioned at the start of the next entry\n     * in the Central Directory.\n     */\n    TinkerZipEntry(byte[] cdeHdrBuf, InputStream cdStream, Charset defaultCharset, boolean isZip64) throws IOException {\n        Streams.readFully(cdStream, cdeHdrBuf, 0, cdeHdrBuf.length);\n        BufferIterator it = HeapBufferIterator.iterator(cdeHdrBuf, 0, cdeHdrBuf.length,\n                ByteOrder.LITTLE_ENDIAN);\n        int sig = it.readInt();\n        if (sig != CENSIG) {\n            TinkerZipFile.throwZipException(\"unknown\", cdStream.available(), \"unknown\", 0, \"Central Directory Entry\", sig);\n        }\n        it.seek(8);\n        int gpbf = it.readShort() & 0xffff;\n        if ((gpbf & TinkerZipFile.GPBF_UNSUPPORTED_MASK) != 0) {\n            throw new ZipException(\"Invalid General Purpose Bit Flag: \" + gpbf);\n        }\n        // If the GPBF_UTF8_FLAG is set then the character encoding is UTF-8 whatever the default\n        // provided.\n        Charset charset = defaultCharset;\n        if ((gpbf & TinkerZipFile.GPBF_UTF8_FLAG) != 0) {\n            charset = Charset.forName(\"UTF-8\");\n        }\n        compressionMethod = it.readShort() & 0xffff;\n        time = it.readShort() & 0xffff;\n        modDate = it.readShort() & 0xffff;\n        // These are 32-bit values in the file, but 64-bit fields in this object.\n        crc = ((long) it.readInt()) & 0xffffffffL;\n        compressedSize = ((long) it.readInt()) & 0xffffffffL;\n        size = ((long) it.readInt()) & 0xffffffffL;\n        int nameLength = it.readShort() & 0xffff;\n        int extraLength = it.readShort() & 0xffff;\n        int commentByteCount = it.readShort() & 0xffff;\n        // This is a 32-bit value in the file, but a 64-bit field in this object.","sourceCodeStart":126,"sourceCodeEnd":162,"githubUrl":"https://github.com/Tencent/tinker/blob/1b7ea02c239840f563ea64fb5bd286eb98d4011e/third-party/tinker-ziputils/src/main/java/com/tencent/tinker/ziputils/ziputil/TinkerZipEntry.java#L126-L162","documentation":"While parsing a central directory entry, TinkerZipEntry reads the general purpose bit flag (GPBF) and rejects the archive if any bit in TinkerZipFile.GPBF_UNSUPPORTED_MASK is set. The mask equals GPBF_ENCRYPTED_FLAG (bit 0), so in practice this exception means the zip entry is encrypted and this reader — like Android's platform ZipFile — does not support encrypted archives.","triggerScenarios":"Opening an encrypted zip (password-protected, PKZIP/WinZip AES or traditional ZipCrypto) with TinkerZipFile or any code path that constructs TinkerZipEntry from a central directory stream; the CDE's flag field has bit 0 set and the exception is thrown during entry enumeration/read.","commonSituations":"Processing user-supplied or third-party archives that were password-protected by default (some Windows/macOS tools); CI fixtures generated with encryption; APKs passed through an 'app lock'/packer tool that re-zips with encryption; strong-encryption flags set by exotic archivers.","solutions":["Re-create the archive without encryption: `zip -Z store`/`zip -r plain.zip dir` (no -e/-P), or in Java write entries with java.util.zip which never encrypts.","If you must consume encrypted zips, pre-decrypt them with a library that supports it (e.g. zip4j) into a plain stream/file before handing them to tinker-ziputils.","Validate archives at ingest: check bit 0 of the GPBF in the central directory and reject early with a clear 'encrypted archives not supported' message."],"exampleFix":"// before: feeding any downloaded archive straight to the reader\nTinkerZipFile zf = new TinkerZipFile(downloadedFile); // throws Invalid GPBF on encrypted zip\n\n// after: detect encryption up front and reject with a clear message\ntry (java.util.zip.ZipFile probe = new java.util.zip.ZipFile(downloadedFile)) {\n    // java.util.zip also refuses encrypted entries; failure here gives an early, clear signal\n}\nTinkerZipFile zf = new TinkerZipFile(downloadedFile);","handlingStrategy":"validation","validationCode":"// Detect the encrypted flag (bit 0 of GPBF) in the central directory before full parse\nboolean isEncryptedZip(java.io.File f) throws java.io.IOException {\n    try (java.util.zip.ZipFile zf = new java.util.zip.ZipFile(f)) {\n        java.util.Enumeration<? extends java.util.zip.ZipEntry> es = zf.entries();\n        while (es.hasMoreElements()) {\n            // platform reader refuses encrypted entries; reaching here means it got past them\n        }\n        return false;\n    } catch (java.util.zip.ZipException e) {\n        return e.getMessage() != null && e.getMessage().toLowerCase().contains(\"encrypt\");\n    }\n}","typeGuard":null,"tryCatchPattern":"try {\n    TinkerZipFile zf = new TinkerZipFile(file);\n} catch (java.util.zip.ZipException e) {\n    if (e.getMessage() != null && e.getMessage().startsWith(\"Invalid General Purpose Bit Flag\")) {\n        throw new IllegalArgumentException(\"encrypted or unsupported zip archives are not accepted: \" + file, e);\n    }\n    throw e;\n}","preventionTips":["Reject password-protected archives at ingest with a clear message.","Standardize on unencrypted archives in build pipelines (no -e/-P flags).","Pre-decrypt with a supporting library (e.g. zip4j) if encrypted input is unavoidable."],"tags":["zip","encryption","gpbf","tinker"],"backgroundTag":null,"analyzedSha":"1b7ea02c239840f563ea64fb5bd286eb98d4011e","analyzedAt":"2026-08-14T15:16:52.110Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}