Skip to content

Commit f338ded

Browse files
committed
Java: treat hash/encrypt/digest methods as sensitive-log sanitizers
The sensitive-log query (CWE-532) lacked sanitizers for hashed or encrypted data, while the sibling cleartext-storage query (CWE-312) already recognized methods with "encrypt", "hash", or "digest" in their names as sanitizers (CleartextStorageQuery.qll:86). This adds an EncryptionBarrier to SensitiveLoggingQuery that applies the same name-based heuristic, making the two queries consistent. Calls like DigestUtils.sha256Hex(password) or hashPassword(secret) are no longer flagged when their results are logged.
1 parent fb8b569 commit f338ded

File tree

4 files changed

+34
-0
lines changed

4 files changed

+34
-0
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: minorAnalysis
3+
---
4+
* The `java/sensitive-log` query now treats method calls whose names contain "encrypt", "hash", or "digest" as sanitizers, consistent with the existing treatment in `java/cleartext-storage-in-log`. This reduces false positives when sensitive data is hashed or encrypted before logging.

java/ql/lib/semmle/code/java/security/SensitiveLoggingQuery.qll

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,19 @@ private class DefaultSensitiveLoggerBarrier extends SensitiveLoggerBarrier {
120120
}
121121
}
122122

123+
/**
124+
* A barrier for sensitive data that has been hashed, encrypted, or digested before logging.
125+
* This is consistent with the treatment of encryption in `CleartextStorageQuery.qll` (CWE-312).
126+
*/
127+
private class EncryptionBarrier extends SensitiveLoggerBarrier {
128+
EncryptionBarrier() {
129+
exists(MethodCall mc |
130+
this.asExpr() = mc and
131+
mc.getMethod().getName().toLowerCase().matches(["%encrypt%", "%hash%", "%digest%"])
132+
)
133+
}
134+
}
135+
123136
/** A data-flow configuration for identifying potentially-sensitive data flowing to a log output. */
124137
module SensitiveLoggerConfig implements DataFlow::ConfigSig {
125138
predicate isSource(DataFlow::Node source) { source instanceof SensitiveLoggerSource }

java/ql/test/query-tests/security/CWE-532/SensitiveLogInfo.expected

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,15 @@
33
| Test.java:12:22:12:52 | ... + ... | Test.java:12:44:12:52 | authToken : String | Test.java:12:22:12:52 | ... + ... | This $@ is written to a log file. | Test.java:12:44:12:52 | authToken | potentially sensitive information |
44
| Test.java:21:22:21:75 | ... + ... | Test.java:21:44:21:52 | authToken : String | Test.java:21:22:21:75 | ... + ... | This $@ is written to a log file. | Test.java:21:44:21:52 | authToken | potentially sensitive information |
55
| Test.java:22:22:22:75 | ... + ... | Test.java:22:44:22:52 | authToken : String | Test.java:22:22:22:75 | ... + ... | This $@ is written to a log file. | Test.java:22:44:22:52 | authToken | potentially sensitive information |
6+
| Test.java:31:21:31:37 | ... + ... | Test.java:31:30:31:37 | password : String | Test.java:31:21:31:37 | ... + ... | This $@ is written to a log file. | Test.java:31:30:31:37 | password | potentially sensitive information |
67
edges
78
| Test.java:11:46:11:53 | password : String | Test.java:11:21:11:53 | ... + ... | provenance | Sink:MaD:2 |
89
| Test.java:12:44:12:52 | authToken : String | Test.java:12:22:12:52 | ... + ... | provenance | Sink:MaD:1 |
910
| Test.java:21:44:21:52 | authToken : String | Test.java:21:44:21:67 | substring(...) : String | provenance | MaD:3 |
1011
| Test.java:21:44:21:67 | substring(...) : String | Test.java:21:22:21:75 | ... + ... | provenance | Sink:MaD:1 |
1112
| Test.java:22:44:22:52 | authToken : String | Test.java:22:44:22:67 | substring(...) : String | provenance | MaD:3 |
1213
| Test.java:22:44:22:67 | substring(...) : String | Test.java:22:22:22:75 | ... + ... | provenance | Sink:MaD:1 |
14+
| Test.java:31:30:31:37 | password : String | Test.java:31:21:31:37 | ... + ... | provenance | Sink:MaD:2 |
1315
models
1416
| 1 | Sink: org.apache.logging.log4j; Logger; true; error; (String); ; Argument[0]; log-injection; manual |
1517
| 2 | Sink: org.apache.logging.log4j; Logger; true; info; (String); ; Argument[0]; log-injection; manual |
@@ -25,4 +27,6 @@ nodes
2527
| Test.java:22:22:22:75 | ... + ... | semmle.label | ... + ... |
2628
| Test.java:22:44:22:52 | authToken : String | semmle.label | authToken : String |
2729
| Test.java:22:44:22:67 | substring(...) : String | semmle.label | substring(...) : String |
30+
| Test.java:31:21:31:37 | ... + ... | semmle.label | ... + ... |
31+
| Test.java:31:30:31:37 | password : String | semmle.label | password : String |
2832
subpaths

java/ql/test/query-tests/security/CWE-532/Test.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,17 @@ void test(String password, String authToken, String username, String nullToken,
2121
logger.error("Auth failed for: " + authToken.substring(1,5) + "..."); // $ Alert
2222
logger.error("Auth failed for: " + authToken.substring(0,8) + "..."); // $ Alert
2323
}
24+
25+
// Tests for hash/encryption sanitizer
26+
void testHashSanitizer(String password, String authToken) {
27+
Logger logger = null;
28+
logger.info("hash: " + hashPassword(password)); // Safe - hashed
29+
logger.info("hash: " + sha256Digest(authToken)); // Safe - digested
30+
logger.info("enc: " + encryptValue(password)); // Safe - encrypted
31+
logger.info("pw: " + password); // $ Alert - not hashed
32+
}
33+
34+
static String hashPassword(String input) { return input; }
35+
static String sha256Digest(String input) { return input; }
36+
static String encryptValue(String input) { return input; }
2437
}

0 commit comments

Comments
 (0)