digikam: 2 new defects (0003 MOAD-0001, 0004 MOAD-0004); lmms: all 5 MOADs CLEAN
digikam-0003 CWE-407: MetaEngine/DMetadata addToXmpTagStringBag and removeFromXmpTagStringBag call QStringList::contains() inside a loop over existing entries — O(O*N) per image during batch metadata write. Fix: build QSet<QString> before the loop for O(1) lookup. 17x speedup at K=200 keywords (unit test PASS). digikam-0004 CWE-312: O2::onVerificationReceived logs the full OAuth2 token exchange POST body (including client_secret_) via qDebug() at GrantFlowAuthorizationCode completion — exposes cloud service credentials in debug logs/stderr for Google Photos, Flickr, OneDrive integrations. Fix: replace full-body dump with redacted log line. lmms: all 5 MOADs CLEAN — std::find uses are non-hot, contains() calls are on QHash/QMap/QSet, no credential logging, no leaked thread context, no unsynchronized cache access.
This commit is contained in:
parent
282282447c
commit
16a8ba0900
5 changed files with 403 additions and 0 deletions
89
defects/digikam/test/DigiKamOAuthSecretLogTest.java
Normal file
89
defects/digikam/test/DigiKamOAuthSecretLogTest.java
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
import java.util.*;
|
||||
import java.util.logging.*;
|
||||
import java.io.*;
|
||||
|
||||
/**
|
||||
* DigiKamOAuthSecretLogTest — digikam-0004
|
||||
*
|
||||
* Reproduces the CWE-312 defect in O2::onVerificationReceived:
|
||||
* when GrantFlowAuthorizationCode completes, the full token exchange
|
||||
* POST body — including client_secret — is logged verbatim via qDebug().
|
||||
*
|
||||
* Models the defective (full body logged) vs fixed (body redacted) behavior,
|
||||
* verifying that the fixed version does not emit the secret.
|
||||
*/
|
||||
public class DigiKamOAuthSecretLogTest {
|
||||
|
||||
// Simulates building the OAuth2 token exchange body (like buildRequestBody)
|
||||
static String buildRequestBody(Map<String, String> params) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (Map.Entry<String, String> e : params.entrySet()) {
|
||||
if (sb.length() > 0) sb.append("&");
|
||||
sb.append(e.getKey()).append("=").append(e.getValue());
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
// Defective: logs full body including client_secret (mirrors o2.cpp line 284)
|
||||
static String defectiveLog(String clientSecret, String code, String clientId, String redirectUri) {
|
||||
Map<String, String> parameters = new LinkedHashMap<>();
|
||||
parameters.put("code", code);
|
||||
parameters.put("client_id", clientId);
|
||||
parameters.put("client_secret", clientSecret);
|
||||
parameters.put("redirect_uri", redirectUri);
|
||||
parameters.put("grant_type", "authorization_code");
|
||||
String data = buildRequestBody(parameters);
|
||||
// Simulates: qDebug() << QString("O2::onVerificationReceived: Exchange access code data:\n%1").arg(data)
|
||||
return "O2::onVerificationReceived: Exchange access code data:\n" + data;
|
||||
}
|
||||
|
||||
// Fixed: logs redacted message (mirrors patch)
|
||||
static String fixedLog(String clientSecret, String code, String clientId, String redirectUri) {
|
||||
// Simulates: qDebug() << "O2::onVerificationReceived: Sending token exchange request (body redacted)"
|
||||
return "O2::onVerificationReceived: Sending token exchange request (body redacted)";
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println("DigiKamOAuthSecretLogTest — digikam-0004 CWE-312");
|
||||
System.out.println("O2::onVerificationReceived logs client_secret in full POST body");
|
||||
System.out.println();
|
||||
|
||||
String clientSecret = "super_secret_oauth2_client_credential_abc123xyz";
|
||||
String code = "auth_code_from_callback";
|
||||
String clientId = "digikam-app-client-id";
|
||||
String redirectUri = "http://localhost:8080/callback";
|
||||
|
||||
// Defective: secret appears in log output
|
||||
String defectiveOutput = defectiveLog(clientSecret, code, clientId, redirectUri);
|
||||
boolean defectiveLeaks = defectiveOutput.contains(clientSecret);
|
||||
System.out.println("Defective log output:");
|
||||
System.out.println(" " + defectiveOutput.replace("\n", "\n "));
|
||||
System.out.println(" Contains secret: " + defectiveLeaks);
|
||||
assert defectiveLeaks : "Defective variant should contain secret in log (test setup error)";
|
||||
System.out.println("PASS: defective variant confirmed to leak secret");
|
||||
|
||||
// Fixed: secret must NOT appear in log output
|
||||
String fixedOutput = fixedLog(clientSecret, code, clientId, redirectUri);
|
||||
boolean fixedLeaks = fixedOutput.contains(clientSecret);
|
||||
System.out.println("\nFixed log output:");
|
||||
System.out.println(" " + fixedOutput);
|
||||
System.out.println(" Contains secret: " + fixedLeaks);
|
||||
assert !fixedLeaks : "Fixed variant must not contain secret in log, but found: " + fixedOutput;
|
||||
System.out.println("PASS: fixed variant does not leak secret");
|
||||
|
||||
// Verify fixed log still contains useful diagnostic info
|
||||
assert fixedOutput.contains("O2::onVerificationReceived") :
|
||||
"Fixed log should still identify the function";
|
||||
assert fixedOutput.contains("redacted") :
|
||||
"Fixed log should indicate body was redacted";
|
||||
System.out.println("PASS: fixed log retains useful diagnostic context");
|
||||
|
||||
// Edge: verify no partial secret leak (first 3 chars truncation check)
|
||||
String secretPrefix3 = clientSecret.substring(0, 3);
|
||||
assert !fixedOutput.contains(secretPrefix3) :
|
||||
"Fixed log should not contain even first 3 chars of secret";
|
||||
System.out.println("PASS: fixed log contains no partial secret fragment");
|
||||
|
||||
System.out.println("\nALL PASS");
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue