What changed, and why it matters
This commit swaps the macOS menu library used by Sparrow Wallet from an older package (centerdevice-nsmenufx) to a newer fork (nsmenufx). The stated reason is to avoid a NullPointerException (NPE). The change also removes several JavaFX internal-access permissions that the old library needed. There is no direct evidence in the commit of a security vulnerability; it reads as a routine dependency update to fix a crash bug.
Treat as a routine maintenance/bug-fix commit unless independent security analysis of the old or new nsmenufx library identifies a vulnerability. Review the new dependency for supply-chain integrity and confirm the NPE fix does not introduce UI state issues on macOS.
Security signals we found
Dependency swap to a maintained fork of a UI library
Removal of multiple --add-opens JavaFX internal module grants
Commit message mentions fixing a NullPointerException
Evidence from the diff
The patch updates build.gradle to replace de.codecentric.centerdevice:centerdevice-nsmenufx:2.1.7 with de.jangassen:nsmenufx:3.1.0, removes related –add-opens JVM arguments for centerdevice.nsmenufx, updates module-info.java to require nsmenufx, and changes AppController.java imports and one call site. The only behavioral code change is removing Platform.runLater(…) around tk.setApplicationMenu(…). The commit message says this is to avoid an NPE, but no exploit path or security impact is described in the diff or supplied references.
Changed components
build.gradle dependency declarationsJVM launch arguments in application and jlink blockssrc/main/java/com/sparrowwallet/sparrow/AppController.java macOS application menu setupsrc/main/java/module-info.java module requirementInspect captured patch +13 / −25
diff --git a/build.gradle b/build.gradle
index 404ddc7..63038eb 100644
--- a/build.gradle
+++ b/build.gradle
@@ -79,7 +79,9 @@ dependencies {
implementation('org.jetbrains.kotlinx:kotlinx-coroutines-javafx:1.10.1') {
exclude group: 'org.jetbrains.kotlin', module: 'kotlin-stdlib-common'
}
- implementation('de.codecentric.centerdevice:centerdevice-nsmenufx:2.1.7')
+ implementation('de.jangassen:nsmenufx:3.1.0') {
+ exclude group: 'net.java.dev.jna', module: 'jna'
+ }
implementation('org.controlsfx:controlsfx:11.1.0' ) {
exclude group: 'org.openjfx', module: 'javafx-base'
exclude group: 'org.openjfx', module: 'javafx-graphics'
@@ -156,11 +158,6 @@ application {
"--add-opens=javafx.controls/javafx.scene.control.cell=com.sparrowwallet.sparrow",
"--add-opens=org.controlsfx.controls/impl.org.controlsfx.skin=com.sparrowwallet.sparrow",
"--add-opens=org.controlsfx.controls/impl.org.controlsfx.skin=javafx.fxml",
- "--add-opens=javafx.graphics/com.sun.javafx.tk=centerdevice.nsmenufx",
- "--add-opens=javafx.graphics/com.sun.javafx.tk.quantum=centerdevice.nsmenufx",
- "--add-opens=javafx.graphics/com.sun.glass.ui=centerdevice.nsmenufx",
- "--add-opens=javafx.controls/com.sun.javafx.scene.control=centerdevice.nsmenufx",
- "--add-opens=javafx.graphics/com.sun.javafx.menu=centerdevice.nsmenufx",
"--add-opens=javafx.graphics/com.sun.glass.ui=com.sparrowwallet.sparrow",
"--add-opens=javafx.graphics/com.sun.javafx.application=com.sparrowwallet.sparrow",
"--add-opens=javafx.graphics/javafx.scene.input=com.sparrowwallet.sparrow",
@@ -171,8 +168,7 @@ application {
"--add-reads=org.flywaydb.core=java.desktop"]
if(os.macOsX) {
- applicationDefaultJvmArgs += ["-Dprism.lcdtext=false", "-Xdock:name=Sparrow",
- "--add-opens=javafx.graphics/com.sun.glass.ui.mac=centerdevice.nsmenufx"]
+ applicationDefaultJvmArgs += ["-Dprism.lcdtext=false", "-Xdock:name=Sparrow"]
}
if(headless) {
applicationDefaultJvmArgs += ["-Dglass.platform=Monocle", "-Dmonocle.platform=Headless", "-Dprism.order=sw"]
@@ -211,11 +207,6 @@ jlink {
"--add-opens=javafx.controls/javafx.scene.control.cell=com.sparrowwallet.sparrow",
"--add-opens=org.controlsfx.controls/impl.org.controlsfx.skin=com.sparrowwallet.sparrow",
"--add-opens=org.controlsfx.controls/impl.org.controlsfx.skin=javafx.fxml",
- "--add-opens=javafx.graphics/com.sun.javafx.tk=centerdevice.nsmenufx",
- "--add-opens=javafx.graphics/com.sun.javafx.tk.quantum=centerdevice.nsmenufx",
- "--add-opens=javafx.graphics/com.sun.glass.ui=centerdevice.nsmenufx",
- "--add-opens=javafx.controls/com.sun.javafx.scene.control=centerdevice.nsmenufx",
- "--add-opens=javafx.graphics/com.sun.javafx.menu=centerdevice.nsmenufx",
"--add-opens=javafx.graphics/com.sun.glass.ui=com.sparrowwallet.sparrow",
"--add-opens=javafx.graphics/javafx.scene.input=com.sparrowwallet.sparrow",
"--add-opens=javafx.graphics/com.sun.javafx.application=com.sparrowwallet.sparrow",
@@ -242,7 +233,7 @@ jlink {
jvmArgs += ["-Djavax.accessibility.assistive_technologies", "-Djavax.accessibility.screen_magnifier_present=false"]
}
if(os.macOsX) {
- jvmArgs += ["-Dprism.lcdtext=false", "--add-opens=javafx.graphics/com.sun.glass.ui.mac=com.sparrowwallet.merged.module", "--add-opens=javafx.graphics/com.sun.glass.ui.mac=centerdevice.nsmenufx"]
+ jvmArgs += ["-Dprism.lcdtext=false", "--add-opens=javafx.graphics/com.sun.glass.ui.mac=com.sparrowwallet.merged.module"]
}
if(headless) {
jvmArgs += ["-Dglass.platform=Monocle", "-Dmonocle.platform=Headless", "-Dprism.order=sw"]
@@ -394,12 +385,6 @@ extraJavaModuleInfo {
requires('java.desktop')
requires('com.sun.jna')
}
- module('de.codecentric.centerdevice:centerdevice-nsmenufx', 'centerdevice.nsmenufx') {
- exports('de.codecentric.centerdevice')
- requires('javafx.base')
- requires('javafx.controls')
- requires('javafx.graphics')
- }
module('net.sourceforge.javacsv:javacsv', 'net.sourceforge.javacsv') {
exports('com.csvreader')
}
diff --git a/src/main/java/com/sparrowwallet/sparrow/AppController.java b/src/main/java/com/sparrowwallet/sparrow/AppController.java
index ceb9d4a..be7ae5a 100644
--- a/src/main/java/com/sparrowwallet/sparrow/AppController.java
+++ b/src/main/java/com/sparrowwallet/sparrow/AppController.java
@@ -31,7 +31,7 @@ import com.sparrowwallet.sparrow.transaction.TransactionView;
import com.sparrowwallet.sparrow.wallet.Entry;
import com.sparrowwallet.sparrow.wallet.WalletController;
import com.sparrowwallet.sparrow.wallet.WalletForm;
-import de.codecentric.centerdevice.MenuToolkit;
+import de.jangassen.MenuToolkit;
import javafx.animation.*;
import javafx.application.Platform;
import javafx.beans.binding.Bindings;
@@ -50,12 +50,14 @@ import javafx.geometry.Side;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.*;
-import javafx.scene.image.Image;
-import javafx.scene.image.ImageView;
+import javafx.scene.control.Label;
+import javafx.scene.control.Menu;
+import javafx.scene.control.MenuItem;
import javafx.scene.input.*;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.stage.*;
+import javafx.stage.Window;
import javafx.util.Duration;
import org.controlsfx.control.Notifications;
import org.controlsfx.control.StatusBar;
@@ -70,6 +72,7 @@ import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.text.ParseException;
import java.util.*;
+import java.util.List;
import java.util.stream.Collectors;
import static com.sparrowwallet.sparrow.AppServices.*;
@@ -463,7 +466,7 @@ public class AppController implements Initializable {
settings, new SeparatorMenuItem(),
tk.createHideMenuItem(SparrowWallet.APP_NAME), tk.createHideOthersMenuItem(), tk.createUnhideAllMenuItem(), new SeparatorMenuItem(),
tk.createQuitMenuItem(SparrowWallet.APP_NAME));
- Platform.runLater(() -> tk.setApplicationMenu(defaultApplicationMenu));
+ tk.setApplicationMenu(defaultApplicationMenu);
fileMenu.getItems().removeIf(item -> item.getStyleClass().contains("osxHide"));
toolsMenu.getItems().removeIf(item -> item.getStyleClass().contains("osxHide"));
diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java
index 3c8073e..28ad25b 100644
--- a/src/main/java/module-info.java
+++ b/src/main/java/module-info.java
@@ -34,7 +34,7 @@ open module com.sparrowwallet.sparrow {
requires com.sparrowwallet.hummingbird;
requires org.fxmisc.flowless;
requires openpnp.capture.java;
- requires centerdevice.nsmenufx;
+ requires nsmenufx;
requires org.jcommander;
requires jul.to.slf4j;
requires net.sourceforge.javacsv;
Why this scored 20/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.