replace yubikeyotp to avoid form-data cve

Signed-off-by: si458 <simonsmith5521@gmail.com>

si458 committed Sep 9, 2025 at 15:38 UTC 6bcf39610ac4ef132a653caefe5a4002835d4ec1
5 files changed +11 -18
docker/Dockerfile
+1 -1
@@ -121,7 +121,7 @@ RUN case "$PREINSTALL_LIBS" in \
121 true|yes|TRUE|YES) \
122 cd meshcentral && \
123 echo -e "----------\nPREINSTALLING LIBRARIES...\n----------"; \
124 - npm install ssh2@1.16.0 nodemailer@6.10.1 image-size@2.0.2 wildleek@2.0.0 otplib@12.0.1 yubikeyotp@0.2.0;; \
124 + npm install ssh2@1.16.0 nodemailer@6.10.1 image-size@2.0.2 wildleek@2.0.0 otplib@12.0.1 yub@0.11.1;; \
125 false|no|FALSE|NO) \
126 echo "Not pre-installing libraries.";; \
127 *) \
meshcentral-config-schema.json
+1 -6
@@ -2785,7 +2785,7 @@
2785 },
2786 "yubikey": {
2787 "type": "object",
2788 - "description": "Yubikey configuration",
2788 + "description": "Yubikey OTP configuration (get API Key from https://upgrade.yubico.com/getapikey/)",
2789 "properties": {
2790 "id": {
2791 "type": "string",
@@ -2794,11 +2794,6 @@
2794 "secret": {
2795 "type": "string",
2796 "description": "Yubikey secret key"
2797 - },
2798 - "proxy": {
2799 - "type": "string",
2800 - "format": "uri",
2801 - "description": "Yubikey proxy URL"
2797 }
2798 },
2799 "required": [
meshcentral.js
+1 -1
@@ -4369,7 +4369,7 @@ function mainStart() {
4369 // Setup 2nd factor authentication
4370 if (config.settings.no2factorauth !== true) {
4371 // Setup YubiKey OTP if configured
4372 - if (yubikey == true) { modules.push('yubikeyotp@0.2.0'); } // Add YubiKey OTP support
4372 + if (yubikey == true) { modules.push('yub@0.11.1'); } // Add YubiKey OTP support (replaced yubikeyotp due to form-data issues)
4373 if (allsspi == false) { modules.push('otplib@12.0.1'); } // Google Authenticator support (v10 supports older NodeJS versions).
4374 }
4375
meshuser.js
+5 -6
@@ -3906,12 +3906,12 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
3906 if ((user.siteadmin != 0xFFFFFFFF) && ((user.siteadmin & 1024) != 0)) return; // If this account is settings locked, return here.
3907
3908 // Yubico API id and signature key can be requested from https://upgrade.yubico.com/getapikey/
3909 - var yubikeyotp = null;
3910 - try { yubikeyotp = require('yubikeyotp'); } catch (ex) { }
3909 + var yub = null;
3910 + try { yub = require('yub'); } catch (ex) { }
3911
3912 // Check if 2-step login is supported
3913 const twoStepLoginSupported = ((parent.parent.config.settings.no2factorauth !== true) && (domain.auth != 'sspi') && (parent.parent.certificates.CommonName.indexOf('.') != -1) && (args.nousers !== true));
3914 - if ((yubikeyotp == null) || (twoStepLoginSupported == false) || (typeof command.otp != 'string')) {
3914 + if ((yub == null) || (twoStepLoginSupported == false) || (typeof command.otp != 'string')) {
3915 ws.send(JSON.stringify({ action: 'otp-hkey-yubikey-add', result: false, name: command.name }));
3916 break;
3917 }
@@ -3925,9 +3925,8 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
3925 // TODO: Check if command.otp is modhex encoded, reject if not.
3926
3927 // Query the YubiKey server to validate the OTP
3928 - var request = { otp: command.otp, id: domain.yubikey.id, key: domain.yubikey.secret, timestamp: true }
3929 - if (domain.yubikey.proxy) { request.requestParams = { proxy: domain.yubikey.proxy }; }
3930 - yubikeyotp.verifyOTP(request, function (err, results) {
3928 + yub.init(domain.yubikey.id, domain.yubikey.secret);
3929 + yub.verify(command.otp, function (err, results) {
3930 if ((results != null) && (results.status == 'OK')) {
3931 var keyIndex = parent.crypto.randomBytes(4).readUInt32BE(0);
3932 var keyId = command.otp.substring(0, 12);
webserver.js
+3 -4
@@ -1073,10 +1073,9 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
1073
1074 // If we have a match, check the OTP
1075 if (match === true) {
1076 - var yubikeyotp = require('yubikeyotp');
1077 - var request = { otp: token, id: domain.yubikey.id, key: domain.yubikey.secret, timestamp: true }
1078 - if (domain.yubikey.proxy) { request.requestParams = { proxy: domain.yubikey.proxy }; }
1079 - yubikeyotp.verifyOTP(request, function (err, results) {
1076 + var yub = require('yub');
1077 + yub.init(domain.yubikey.id, domain.yubikey.secret);
1078 + yub.verify(token, function (err, results) {
1079 if ((results != null) && (results.status == 'OK')) {
1080 parent.debug('web', 'checkUserOneTimePassword: success (Yubikey).');
1081 func(true, { twoFactorType: 'hwotp' });