java-topology/defects/zesarux-0001/test/ZesaruxZrcpCredentialLogTest.java
russell@unturf.com 2f0da6752a zesarux: 1 CWE-312 defect, MOAD 0001/0002/0003/0005 CLEAN
yabause: 1 CWE-312 defect, MOAD 0001/0002/0003/0005 CLEAN
vita3k-0001: unit test added for pre-existing CWE-407 patch
2026-03-31 19:29:16 -04:00

153 lines
5.9 KiB
Java

import java.util.*;
import java.util.regex.*;
/**
* Unit test for ZEsarUX CWE-312 defect zesarux-0001.
*
* zesarux-0001: The ZRCP remote command dispatcher logs the full command
* string and parameter string verbatim at VERBOSE_DEBUG level. ZENG
* multiplayer commands carry creator_pass and user_pass as inline parameters
* (e.g. "authorize-join SECRET123 0 rw"). Any debug log or terminal capture
* will contain the plaintext session credential.
*
* Models the C logging behaviour and verifies the fix (redaction).
*/
public class ZesaruxZrcpCredentialLogTest {
/** Simulates a debug log sink. */
static class DebugLog {
private final List<String> entries = new ArrayList<>();
void log(String msg) {
entries.add(msg);
}
List<String> getEntries() {
return Collections.unmodifiableList(entries);
}
boolean anyEntryContains(String substring) {
for (String e : entries) {
if (e.contains(substring)) return true;
}
return false;
}
}
// ---------------------------------------------------------------
// DEFECTIVE: logs full command and parameter strings verbatim
// ---------------------------------------------------------------
static void defectiveProcessCommand(DebugLog log, String command) {
int len = command.length();
// Line 3884: logs full command including inline password
log.log(String.format("Remote command: length: %d [%s]", len, command));
// Split into verb + parameters (simple split on first space)
int spaceIdx = command.indexOf(' ');
String verb = (spaceIdx >= 0) ? command.substring(0, spaceIdx) : command;
String params = (spaceIdx >= 0) ? command.substring(spaceIdx + 1) : "";
log.log(String.format("Remote command without parameters: length: %d [%s]",
verb.length(), verb));
// Line 3963: logs parameters verbatim — exposes password as first token
log.log(String.format("Remote command parameters: length: %d [%s]",
params.length(), params));
}
// ---------------------------------------------------------------
// FIXED: logs length only, redacts parameter values
// ---------------------------------------------------------------
static void fixedProcessCommand(DebugLog log, String command) {
int len = command.length();
// Patched line 3884: length only, no body
log.log(String.format("Remote command: length: %d", len));
int spaceIdx = command.indexOf(' ');
String verb = (spaceIdx >= 0) ? command.substring(0, spaceIdx) : command;
String params = (spaceIdx >= 0) ? command.substring(spaceIdx + 1) : "";
log.log(String.format("Remote command without parameters: length: %d [%s]",
verb.length(), verb));
// Patched line 3963: parameter length + REDACTED placeholder
log.log(String.format("Remote command parameters: length: %d [REDACTED]",
params.length()));
}
// ---------------------------------------------------------------
// ZENG commands that carry a password as first or later parameter
// ---------------------------------------------------------------
static final String[][] CREDENTIAL_COMMANDS = {
{"authorize-join", "CREATORPASS_ALPHA 0 rw"},
{"destroy-room", "CREATORPASS_BETA 1"},
{"get-keys", "USERPASS_GAMMA 0"},
{"kick", "CREATORPASS_DELTA 0 uuid-1234"},
{"leave", "0 USERPASS_EPSILON uuid-5678"},
{"rename-room", "CREATORPASS_ZETA 0 MyRoom"},
{"put-snapshot", "CREATORPASS_ETA 0 DEADBEEF"},
{"send-keys", "USERPASS_THETA 0 uuid-9999 65 1 0"},
};
public static void main(String[] args) {
int pass = 0;
int fail = 0;
for (String[] entry : CREDENTIAL_COMMANDS) {
String verb = entry[0];
String params = entry[1];
// Extract the password token (first token of params)
String password = params.split(" ")[0];
String command = verb + " " + params;
// -- DEFECTIVE: password must appear in log --
DebugLog defLog = new DebugLog();
defectiveProcessCommand(defLog, command);
boolean defectiveExposes = defLog.anyEntryContains(password);
if (defectiveExposes) {
System.out.println("PASS (defect confirmed): " + verb
+ " exposes '" + password + "' in log");
pass++;
} else {
System.out.println("FAIL (defect NOT confirmed): " + verb
+ " did not expose '" + password + "' — test is wrong");
fail++;
}
// -- FIXED: password must NOT appear in log --
DebugLog fixLog = new DebugLog();
fixedProcessCommand(fixLog, command);
boolean fixedExposes = fixLog.anyEntryContains(password);
if (!fixedExposes) {
System.out.println("PASS (fix confirmed): " + verb
+ " does NOT expose '" + password + "' after fix");
pass++;
} else {
System.out.println("FAIL (fix broken): " + verb
+ " still exposes '" + password + "' after fix");
fail++;
}
// -- FIXED: [REDACTED] placeholder must appear --
boolean hasRedacted = fixLog.anyEntryContains("[REDACTED]");
if (hasRedacted) {
System.out.println("PASS (redaction marker present): " + verb);
pass++;
} else {
System.out.println("FAIL (no redaction marker): " + verb);
fail++;
}
}
System.out.println();
System.out.println("Results: " + pass + " passed, " + fail + " failed");
if (fail > 0) {
System.exit(1);
}
}
}