remove unnecessary zbar native libraries
What changed, and why it matters
This commit removes pre-packaged native ZBar barcode-scanning libraries from the Sparrow Wallet application and switches to a Java-only ZBar implementation. It also tightens the permissions of temporary directories created when loading native libraries, so only the owner can access them. The change reduces the attack surface from shipping opaque binary libraries and fixes a potential local information-disclosure weakness in temp directory creation.
Review the jzbar dependency's own native-library loading and temp-file handling to ensure it does not reintroduce the removed risks. Verify that createOwnerOnlyDirectory() behaves correctly on all supported platforms, including Windows fallback and POSIX-limited filesystems. Consider auditing other uses of NativeUtils for similar temp-directory weaknesses.
Security signals we found
Removal of bundled opaque native binaries reduces supply-chain and binary-integrity risk
NativeUtils temp directory now created with owner-only POSIX permissions
Elimination of manual JAR-extraction and loading of native libraries for ZBar
Potential fix for local privilege/information disclosure via world-accessible temp directories
Evidence from the diff
The patch deletes bundled libzbar.so, libzbar.dylib, zbar.dll and iconv-2.dll binaries and removes the manual NativeUtils.loadLibraryFromJar() logic from ZBar.java. The application now relies on the jzbar Java library’s own native loading path. In NativeUtils.java, createTempDirectory() is changed to use a new createOwnerOnlyDirectory() helper that creates directories with POSIX owner-only permissions (rwx------) on Unix-like systems, falling back to mkdirs() if POSIX attributes are unsupported. This addresses a classic insecure-temp-directory issue where world-readable/writable directories could expose extracted native libraries or other sensitive files to other local users.
Changed components
src/main/java/com/sparrowwallet/sparrow/io/ZBar.javasrc/main/java/com/sparrowwallet/sparrow/net/NativeUtils.javasrc/main/resources/native/linux/aarch64/libzbar.sosrc/main/resources/native/linux/x64/libzbar.sosrc/main/resources/native/osx/aarch64/libzbar.dylibsrc/main/resources/native/osx/x64/libzbar.dylibsrc/main/resources/native/windows/x64/iconv-2.dllsrc/main/resources/native/windows/x64/zbar.dllInspect captured patch +33 / −39
diff --git a/src/main/java/com/sparrowwallet/sparrow/io/ZBar.java b/src/main/java/com/sparrowwallet/sparrow/io/ZBar.java
index 27b42b1..f1e099e 100644
--- a/src/main/java/com/sparrowwallet/sparrow/io/ZBar.java
+++ b/src/main/java/com/sparrowwallet/sparrow/io/ZBar.java
@@ -4,7 +4,6 @@ import io.github.doblon8.jzbar.Config;
import io.github.doblon8.jzbar.Image;
import io.github.doblon8.jzbar.ImageScanner;
import io.github.doblon8.jzbar.SymbolType;
-import com.sparrowwallet.sparrow.net.NativeUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -15,18 +14,8 @@ import java.awt.image.DataBufferByte;
public class ZBar {
private static final Logger log = LoggerFactory.getLogger(ZBar.class);
- private final static boolean enabled;
-
- static { // static initializer
- if(com.sparrowwallet.sparrow.io.Config.get().isUseZbar()) {
- enabled = loadLibrary();
- } else {
- enabled = false;
- }
- }
-
public static boolean isEnabled() {
- return enabled;
+ return com.sparrowwallet.sparrow.io.Config.get().isUseZbar();
}
public static Scan scan(BufferedImage bufferedImage) {
@@ -93,31 +82,6 @@ public class ZBar {
return outputData;
}
- private static boolean loadLibrary() {
- try {
- String osName = System.getProperty("os.name");
- String osArch = System.getProperty("os.arch");
- if(osName.startsWith("Mac") && osArch.equals("aarch64")) {
- NativeUtils.loadLibraryFromJar("/native/osx/aarch64/libzbar.dylib");
- } else if(osName.startsWith("Mac")) {
- NativeUtils.loadLibraryFromJar("/native/osx/x64/libzbar.dylib");
- } else if(osName.startsWith("Windows")) {
- NativeUtils.loadLibraryFromJar("/native/windows/x64/iconv-2.dll");
- NativeUtils.loadLibraryFromJar("/native/windows/x64/zbar.dll");
- } else if(osArch.equals("aarch64")) {
- NativeUtils.loadLibraryFromJar("/native/linux/aarch64/libzbar.so");
- } else {
- NativeUtils.loadLibraryFromJar("/native/linux/x64/libzbar.so");
- }
-
- return true;
- } catch(Exception e) {
- log.warn("Could not load ZBar native libraries, disabling. " + e.getMessage());
- }
-
- return false;
- }
-
private static byte[] getRawBytes(String str) {
char[] chars = str.toCharArray();
byte[] bytes = new byte[chars.length];
diff --git a/src/main/java/com/sparrowwallet/sparrow/net/NativeUtils.java b/src/main/java/com/sparrowwallet/sparrow/net/NativeUtils.java
index 1f3c2dd..e4fa45c 100644
--- a/src/main/java/com/sparrowwallet/sparrow/net/NativeUtils.java
+++ b/src/main/java/com/sparrowwallet/sparrow/net/NativeUtils.java
@@ -1,11 +1,17 @@
package com.sparrowwallet.sparrow.net;
+import com.sparrowwallet.drongo.OsType;
+
import java.io.*;
import java.nio.file.FileSystemNotFoundException;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.ProviderNotFoundException;
import java.nio.file.StandardCopyOption;
+import java.nio.file.attribute.PosixFilePermission;
+import java.nio.file.attribute.PosixFilePermissions;
+import java.util.EnumSet;
+import java.util.Set;
/**
* A simple library class which helps with loading dynamic libraries stored in the
@@ -111,9 +117,33 @@ public class NativeUtils {
String tempDir = System.getProperty("java.io.tmpdir");
File generatedDir = new File(tempDir, prefix + System.nanoTime());
- if (!generatedDir.mkdir())
+ if(!createOwnerOnlyDirectory(generatedDir)) {
throw new IOException("Failed to create temp directory " + generatedDir.getName());
+ }
return generatedDir;
}
+
+ public static boolean createOwnerOnlyDirectory(File directory) throws IOException {
+ try {
+ if(OsType.getCurrent() == OsType.WINDOWS) {
+ Files.createDirectories(directory.toPath());
+ return true;
+ }
+
+ Files.createDirectories(directory.toPath(), PosixFilePermissions.asFileAttribute(getDirectoryOwnerOnlyPosixFilePermissions()));
+ return true;
+ } catch(UnsupportedOperationException e) {
+ return directory.mkdirs();
+ }
+ }
+
+ private static Set<PosixFilePermission> getDirectoryOwnerOnlyPosixFilePermissions() {
+ Set<PosixFilePermission> ownerOnly = EnumSet.noneOf(PosixFilePermission.class);
+ ownerOnly.add(PosixFilePermission.OWNER_READ);
+ ownerOnly.add(PosixFilePermission.OWNER_WRITE);
+ ownerOnly.add(PosixFilePermission.OWNER_EXECUTE);
+
+ return ownerOnly;
+ }
}
diff --git a/src/main/resources/native/linux/aarch64/libzbar.so b/src/main/resources/native/linux/aarch64/libzbar.so
deleted file mode 100755
index eae8e05..0000000
Binary files a/src/main/resources/native/linux/aarch64/libzbar.so and /dev/null differ
diff --git a/src/main/resources/native/linux/x64/libzbar.so b/src/main/resources/native/linux/x64/libzbar.so
deleted file mode 100755
index dc8fc98..0000000
Binary files a/src/main/resources/native/linux/x64/libzbar.so and /dev/null differ
diff --git a/src/main/resources/native/osx/aarch64/libzbar.dylib b/src/main/resources/native/osx/aarch64/libzbar.dylib
deleted file mode 100755
index 3ef72ea..0000000
Binary files a/src/main/resources/native/osx/aarch64/libzbar.dylib and /dev/null differ
diff --git a/src/main/resources/native/osx/x64/libzbar.dylib b/src/main/resources/native/osx/x64/libzbar.dylib
deleted file mode 100755
index d8426d6..0000000
Binary files a/src/main/resources/native/osx/x64/libzbar.dylib and /dev/null differ
diff --git a/src/main/resources/native/windows/x64/iconv-2.dll b/src/main/resources/native/windows/x64/iconv-2.dll
deleted file mode 100644
index 700561a..0000000
Binary files a/src/main/resources/native/windows/x64/iconv-2.dll and /dev/null differ
diff --git a/src/main/resources/native/windows/x64/zbar.dll b/src/main/resources/native/windows/x64/zbar.dll
deleted file mode 100644
index 2cc4384..0000000
Binary files a/src/main/resources/native/windows/x64/zbar.dll and /dev/null differ
Why this scored 28/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.