{"record":{"id":"a6de7901b2f15237","repo":"Tencent/tinker","slug":"sharesecuritycheck-file-s-size-d-verifypatchmet-a6de79","errorCode":null,"errorMessage":"ShareSecurityCheck file %s, size %d verifyPatchMetaSignature fail","messagePattern":"ShareSecurityCheck file (.+?), size (.+?) verifyPatchMetaSignature fail","errorType":"exception","errorClass":"TinkerRuntimeException","httpStatus":null,"severity":"critical","filePath":"tinker-android/tinker-android-loader/src/main/java/com/tencent/tinker/loader/shareutil/ShareSecurityCheck.java","lineNumber":130,"sourceCode":"\n                final String name = jarEntry.getName();\n                if (name.startsWith(\"META-INF/\")) {\n                    continue;\n                }\n                //for faster, only check the meta.txt files\n                //we will check other files's md5 written in meta files\n                if (!name.endsWith(ShareConstants.META_SUFFIX)) {\n                    continue;\n                }\n                metaContentMap.put(name, SharePatchFileUtil.loadDigestes(jarFile, jarEntry));\n                Certificate[] certs = jarEntry.getCertificates();\n\n                if (certs == null || !check(path, certs)) {\n                    return false;\n                }\n            }\n        } catch (Exception e) {\n            throw new TinkerRuntimeException(\n                String.format(\"ShareSecurityCheck file %s, size %d verifyPatchMetaSignature fail\", path.getAbsolutePath(), path.length()), e);\n        } finally {\n            try {\n                if (jarFile != null) {\n                    jarFile.close();\n                }\n            } catch (IOException e) {\n                ShareTinkerLog.e(TAG, path.getAbsolutePath(), e);\n            }\n        }\n        return true;\n    }\n\n\n    // verify the signature of the Apk\n    private boolean check(File path, Certificate[] certs) {\n        if (certs.length > 0) {\n            for (int i = certs.length - 1; i >= 0; i--) {","sourceCodeStart":112,"sourceCodeEnd":148,"githubUrl":"https://github.com/Tencent/tinker/blob/1b7ea02c239840f563ea64fb5bd286eb98d4011e/tinker-android/tinker-android-loader/src/main/java/com/tencent/tinker/loader/shareutil/ShareSecurityCheck.java#L112-L148","documentation":"ShareSecurityCheck.verifyPatchMetaSignature opens the patch zip and validates that every *-meta entry is signed by a certificate matching the app's own signature. Any exception during iteration (broken zip, missing entry, cert read) is wrapped as TinkerRuntimeException(\"ShareSecurityCheck file %s, size %d verifyPatchMetaSignature fail\"). Signature mismatch itself returns false; this throw means the check could not even complete.","triggerScenarios":"verifyPatchMetaSignature(path) when JarFile iteration or entry reading throws — truncated/invalid patch zip, unreadable meta entries, or filesystem errors reading the patch file.","commonSituations":"Corrupted or partially downloaded patch package; patch zip repacked without proper signing/v2 signature (or signed with a different key than the app); storage errors; patches built with tools that strip entry certificates.","solutions":["Re-download or rebuild the patch package and verify its md5 against the server-side value before loading.","Sign the patch with the same certificate as the base APK and keep zip signing intact (no post-processing that strips signatures).","Catch TinkerRuntimeException around patch verification and treat the patch as invalid.","Check the chained cause: zip format error vs IO error to decide re-download vs rebuild."],"exampleFix":"// before\nsecurityCheck.verifyPatchMetaSignature(patchFile);\n// after\ntry {\n    if (!securityCheck.verifyPatchMetaSignature(patchFile)) {\n        listener.onPatchPackageCheckFail(loadedPatch.getPatchFile(), PackageUtils.ERROR_PACKAGE_CHECK_SIGNATURE_FAIL);\n        return;\n    }\n} catch (TinkerRuntimeException e) {\n    listener.onPatchPackageCheckFail(patchFile, PackageUtils.ERROR_PACKAGE_CHECK_OK);\n}","handlingStrategy":"validation","validationCode":"// Verify patch package integrity before security check\nif (!patchFile.exists() || patchFile.length() == 0) { /* reject */ }\nif (expectedMd5 != null && !expectedMd5.equals(SharePatchFileUtil.getMD5(patchFile))) {\n    // corrupted download: reject before verifyPatchMetaSignature\n}","typeGuard":null,"tryCatchPattern":"try {\n    if (!securityCheck.verifyPatchMetaSignature(patchFile)) {\n        // signature mismatch: reject patch (returns false)\n    }\n} catch (TinkerRuntimeException e) {\n    // verification could not complete (bad zip/io): reject and re-download\n}","preventionTips":["Verify patch md5 against the server value before loading.","Sign patches with the app's own keystore; never post-process the zip in ways that strip signatures.","Use Tinker's LoadListener callbacks (onLoadPackageCheckFail) instead of letting exceptions propagate."],"tags":["android","tinker","security","signature","patch"],"backgroundTag":null,"analyzedSha":"1b7ea02c239840f563ea64fb5bd286eb98d4011e","analyzedAt":"2026-08-14T15:16:52.110Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}