2323import java .io .IOException ;
2424import java .io .InputStream ;
2525import java .nio .charset .StandardCharsets ;
26+ import java .util .regex .Matcher ;
27+ import java .util .regex .Pattern ;
2628
2729import org .apache .commons .io .IOUtils ;
2830import org .apache .commons .lang3 .StringUtils ;
@@ -40,6 +42,20 @@ public class SshHelper {
4042 private static final int DEFAULT_CONNECT_TIMEOUT = 180000 ;
4143 private static final int DEFAULT_KEX_TIMEOUT = 60000 ;
4244 private static final int DEFAULT_WAIT_RESULT_TIMEOUT = 120000 ;
45+ private static final String MASKED_VALUE = "*****" ;
46+
47+ private static final Pattern [] SENSITIVE_COMMAND_PATTERNS = new Pattern [] {
48+ Pattern .compile ("(?i)(\\ s+-p\\ s+['\" ])([^'\" ]*)(['\" ])" ),
49+ Pattern .compile ("(?i)(\\ s+-p\\ s+)([^\\ s]+)" ),
50+ Pattern .compile ("(?i)(\\ s+-p=['\" ])([^'\" ]*)(['\" ])" ),
51+ Pattern .compile ("(?i)(\\ s+-p=)([^\\ s]+)" ),
52+ Pattern .compile ("(?i)(--password=['\" ])([^'\" ]*)(['\" ])" ),
53+ Pattern .compile ("(?i)(--password=)([^\\ s]+)" ),
54+ Pattern .compile ("(?i)(--password\\ s+['\" ])([^'\" ]*)(['\" ])" ),
55+ Pattern .compile ("(?i)(--password\\ s+)([^\\ s]+)" ),
56+ Pattern .compile ("(?i)(\\ s+-u\\ s+['\" ][^,'\" :]+[,:])([^'\" ]*)(['\" ])" ),
57+ Pattern .compile ("(?i)(\\ s+-u\\ s+[^\\ s,:]+[,:])([^\\ s]+)" )
58+ };
4359
4460 protected static Logger LOGGER = LogManager .getLogger (SshHelper .class );
4561
@@ -145,7 +161,7 @@ public static void scpTo(String host, int port, String user, File pemKeyFile, St
145161 }
146162
147163 public static void scpTo (String host , int port , String user , File pemKeyFile , String password , String remoteTargetDirectory , String [] localFiles , String fileMode ,
148- int connectTimeoutInMs , int kexTimeoutInMs ) throws Exception {
164+ int connectTimeoutInMs , int kexTimeoutInMs ) throws Exception {
149165
150166 com .trilead .ssh2 .Connection conn = null ;
151167 com .trilead .ssh2 .SCPClient scpClient = null ;
@@ -291,13 +307,16 @@ public static Pair<Boolean, String> sshExecute(String host, int port, String use
291307 }
292308
293309 if (sess .getExitStatus () == null ) {
294- //Exit status is NOT available. Returning failure result.
295- LOGGER .error (String .format ("SSH execution of command %s has no exit status set. Result output: %s" , command , result ));
310+ // Exit status is NOT available. Returning failure result.
311+ LOGGER .error (String .format ("SSH execution of command %s has no exit status set. Result output: %s" ,
312+ sanitizeForLogging (command ), sanitizeForLogging (result )));
296313 return new Pair <Boolean , String >(false , result );
297314 }
298315
299316 if (sess .getExitStatus () != null && sess .getExitStatus ().intValue () != 0 ) {
300- LOGGER .error (String .format ("SSH execution of command %s has an error status code in return. Result output: %s" , command , result ));
317+ LOGGER .error (String .format (
318+ "SSH execution of command %s has an error status code in return. Result output: %s" ,
319+ sanitizeForLogging (command ), sanitizeForLogging (result )));
301320 return new Pair <Boolean , String >(false , result );
302321 }
303322 return new Pair <Boolean , String >(true , result );
@@ -366,4 +385,44 @@ protected static void throwSshExceptionIfStdoutOrStdeerIsNull(InputStream stdout
366385 throw new SshException (msg );
367386 }
368387 }
388+
389+ private static String sanitizeForLogging (String value ) {
390+ if (value == null ) {
391+ return null ;
392+ }
393+ String masked = maskSensitiveValue (value );
394+ String cleaned = com .cloud .utils .StringUtils .cleanString (masked );
395+ return cleaned != null ? cleaned : masked ;
396+ }
397+
398+ private static String maskSensitiveValue (String value ) {
399+ String masked = value ;
400+ for (Pattern pattern : SENSITIVE_COMMAND_PATTERNS ) {
401+ masked = replaceWithMask (masked , pattern );
402+ }
403+ return masked ;
404+ }
405+
406+ private static String replaceWithMask (String value , Pattern pattern ) {
407+ Matcher matcher = pattern .matcher (value );
408+ if (!matcher .find ()) {
409+ return value ;
410+ }
411+
412+ StringBuffer buffer = new StringBuffer ();
413+ do {
414+ StringBuilder replacement = new StringBuilder ();
415+ replacement .append (matcher .group (1 ));
416+ if (matcher .groupCount () >= 3 ) {
417+ replacement .append (MASKED_VALUE );
418+ replacement .append (matcher .group (matcher .groupCount ()));
419+ } else {
420+ replacement .append (MASKED_VALUE );
421+ }
422+ matcher .appendReplacement (buffer , Matcher .quoteReplacement (replacement .toString ()));
423+ } while (matcher .find ());
424+
425+ matcher .appendTail (buffer );
426+ return buffer .toString ();
427+ }
369428}
0 commit comments