From a0f1501eddfa124ee46c7821e24f8d388e094ec3 Mon Sep 17 00:00:00 2001 From: Nate Chadwick <263952448+natechadwick-intsof@users.noreply.github.com> Date: Fri, 28 Aug 2026 20:04:27 -0400 Subject: [PATCH] fix(security): T2.x hardening: drop javafaker in SecureStringUtils (closes 16 SnakeYAML CVEs) (issue #98) The transitive snakeyaml:1.23-android dep that the analysis flagged with 16 CVEs comes from com.github.javafaker:javafaker:1.0.2 (stuck at that version since Feb 2020). It is NOT from commons-beanutils (issue #91 was closed as out-of-date -- commons-beanutils 1.11.0 is the latest 1.x and does not declare SnakeYAML). The single production use of javafaker is SecureStringUtils.generateRandomPassword(), which asked for "6-20 random alphanumeric chars with 0-5 special-char substitutions." That is a direct fit for SecureRandom. Rewrote the method body and removed javafaker from modules/perc-security-utils/pom.xml. The two remaining javafaker usages (PSDefaultPasswordEncryptionBeanTest in sitemanage, PSMetadataQueryServiceTest in metadata) are already test in their own poms and continue to work unchanged. Verified: - ./mvn-env.sh clean install -DskipTests -pl modules/perc-security-utils -am BUILD SUCCESS - dependency:tree -pl modules/perc-security-utils -Dincludes=org.yaml:snakeyaml,com.github.javafaker returns empty (both deps are gone from the production classpath) - TestSecureStringUtils (14 tests, 0 failures, 1 skipped) passes - PSDefaultPasswordEncryptionBeanTest (1 test, 0 failures) passes - PSMetadataQueryServiceTest (compiles and runs) passes Closes 16 CVEs in the analysis report that were attributed to snakeyaml:1.23-android. > Co-Authored by Mavis v1.0.0 using minimax-m3 with agent mavis. --- modules/perc-security-utils/pom.xml | 5 --- .../security/SecureStringUtils.java | 35 +++++++++++++++---- 2 files changed, 29 insertions(+), 11 deletions(-) diff --git a/modules/perc-security-utils/pom.xml b/modules/perc-security-utils/pom.xml index c4dc0f93a3..12d26305a3 100644 --- a/modules/perc-security-utils/pom.xml +++ b/modules/perc-security-utils/pom.xml @@ -57,11 +57,6 @@ jasypt compile - - com.github.javafaker - javafaker - 1.0.2 - org.apache.commons commons-math3 diff --git a/modules/perc-security-utils/src/main/java/com/percussion/security/SecureStringUtils.java b/modules/perc-security-utils/src/main/java/com/percussion/security/SecureStringUtils.java index 0fc213dad2..4545f1f680 100644 --- a/modules/perc-security-utils/src/main/java/com/percussion/security/SecureStringUtils.java +++ b/modules/perc-security-utils/src/main/java/com/percussion/security/SecureStringUtils.java @@ -16,7 +16,6 @@ package com.percussion.security; -import com.github.javafaker.Faker; import com.ibm.icu.text.Normalizer2; import com.percussion.error.PSExceptionUtils; import java.io.IOException; @@ -1509,13 +1508,37 @@ public static String sanitizeStringForHTML(String str) { return Encode.forHtml(str); } + /** Alphanumeric alphabet for {@link #generateRandomPassword()}. */ + private static final char[] PASSWORD_ALPHABET = + ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789").toCharArray(); + + /** Special characters that may replace positions in a generated password. */ + private static final char[] PASSWORD_SPECIALS = new char[] {'@', '$', '%', '^', '&', '*'}; + + /** + * Generates a random password of 6-20 alphanumeric characters with 0-5 of the positions + * overwritten by a special character ({@code @ $ % ^ & *}). All randomness is sourced from {@link + * SecureRandom} via {@link #getSecureRandom()}. + * + *

Previously this method used {@code com.github.javafaker.Faker.lorem().characters(...)} for + * the alphanumeric base, which transitively pulled in {@code org.yaml:snakeyaml:1.23-android} (16 + * CVEs). Replaced with a direct {@link SecureRandom} draw in this slice (issue #98). + */ public static String generateRandomPassword() { - Faker f = Faker.instance(getSecureRandom()); + SecureRandom random = getSecureRandom(); + + // Length 6-20 inclusive (was f.lorem().characters(6, 20, ...)). + int length = 6 + random.nextInt(15); + char[] password = new char[length]; + for (int i = 0; i < length; i++) { + password[i] = PASSWORD_ALPHABET[random.nextInt(PASSWORD_ALPHABET.length)]; + } - char[] password = f.lorem().characters(6, 20, true, true).toCharArray(); - char[] special = new char[] {'@', '$', '%', '^', '&', '*'}; - for (int i = 0; i < f.random().nextInt(6); i++) { - password[f.random().nextInt(password.length)] = special[f.random().nextInt(special.length)]; + // 0-5 positions get overwritten with a special char (was f.random().nextInt(6)). + int specials = random.nextInt(6); + for (int i = 0; i < specials; i++) { + password[random.nextInt(password.length)] = + PASSWORD_SPECIALS[random.nextInt(PASSWORD_SPECIALS.length)]; } return new String(password); }