diff --git a/rust/ql/lib/codeql/rust/security/HardcodedCryptographicValueExtensions.qll b/rust/ql/lib/codeql/rust/security/HardcodedCryptographicValueExtensions.qll index ea57d9427338..768f684cea5b 100644 --- a/rust/ql/lib/codeql/rust/security/HardcodedCryptographicValueExtensions.qll +++ b/rust/ql/lib/codeql/rust/security/HardcodedCryptographicValueExtensions.qll @@ -71,6 +71,11 @@ module HardcodedCryptographicValue { or isConstant(e.(ArrayRepeatExpr).getRepeatOperand()) // e.g. `[0; 10]` or + // a match expression with one or more constant arms; taint would reach here + // anyway, but we make it a source to avoid reporting many similar results + // on each match arm. + isConstant(e.(MatchExpr).getMatchArmList().getAnArm().getExpr()) + or // e.g. `const MY_CONST: u64 = ...` // the constant initializer / body is the preferred source location for flow paths, when available. e = any(Const c).getBody() diff --git a/rust/ql/src/change-notes/2026-08-25-hardcoded-cryptographic-match-expressions.md b/rust/ql/src/change-notes/2026-08-25-hardcoded-cryptographic-match-expressions.md new file mode 100644 index 000000000000..b2c71664f87a --- /dev/null +++ b/rust/ql/src/change-notes/2026-08-25-hardcoded-cryptographic-match-expressions.md @@ -0,0 +1,5 @@ +--- +category: minorAnalysis +--- +* The `rust/hard-coded-cryptographic-value` query has been adjusted to produce +fewer results in certain situations where many results were being produced with very similar source locations. diff --git a/rust/ql/test/query-tests/security/CWE-798/HardcodedCryptographicValue.expected b/rust/ql/test/query-tests/security/CWE-798/HardcodedCryptographicValue.expected index 3290d7bca875..d77634d1fd9e 100644 --- a/rust/ql/test/query-tests/security/CWE-798/HardcodedCryptographicValue.expected +++ b/rust/ql/test/query-tests/security/CWE-798/HardcodedCryptographicValue.expected @@ -8,8 +8,9 @@ | test_cipher.rs:73:19:73:26 | [0u8; 32] | test_cipher.rs:73:19:73:26 | [0u8; 32] | test_cipher.rs:74:46:74:51 | const2 | This hard-coded value is used as $@. | test_cipher.rs:74:46:74:51 | const2 | a key | | test_cookie.rs:17:28:17:34 | [0; 64] | test_cookie.rs:17:28:17:34 | [0; 64] | test_cookie.rs:18:26:18:32 | &array1 | This hard-coded value is used as $@. | test_cookie.rs:18:26:18:32 | &array1 | a key | | test_cookie.rs:21:28:21:34 | [0; 64] | test_cookie.rs:21:28:21:34 | [0; 64] | test_cookie.rs:22:26:22:32 | &array2 | This hard-coded value is used as $@. | test_cookie.rs:22:26:22:32 | &array2 | a key | -| test_cookie.rs:38:28:38:36 | [0u8; 64] | test_cookie.rs:38:28:38:36 | [0u8; 64] | test_cookie.rs:42:34:42:39 | array2 | This hard-coded value is used as $@. | test_cookie.rs:42:34:42:39 | array2 | a key | -| test_cookie.rs:49:23:49:25 | 0u8 | test_cookie.rs:49:23:49:25 | 0u8 | test_cookie.rs:53:34:53:39 | array3 | This hard-coded value is used as $@. | test_cookie.rs:53:34:53:39 | array3 | a key | +| test_cookie.rs:25:16:29:5 | match ... { ... } | test_cookie.rs:25:16:29:5 | match ... { ... } | test_cookie.rs:30:26:30:40 | str3.as_bytes() | This hard-coded value is used as $@. | test_cookie.rs:30:26:30:40 | str3.as_bytes() | a key | +| test_cookie.rs:46:28:46:36 | [0u8; 64] | test_cookie.rs:46:28:46:36 | [0u8; 64] | test_cookie.rs:50:34:50:39 | array2 | This hard-coded value is used as $@. | test_cookie.rs:50:34:50:39 | array2 | a key | +| test_cookie.rs:57:23:57:25 | 0u8 | test_cookie.rs:57:23:57:25 | 0u8 | test_cookie.rs:61:34:61:39 | array3 | This hard-coded value is used as $@. | test_cookie.rs:61:34:61:39 | array3 | a key | | test_heuristic.rs:38:25:38:30 | 0xFFFF | test_heuristic.rs:38:25:38:30 | 0xFFFF | test_heuristic.rs:81:22:81:31 | MY_CONST_1 | This hard-coded value is used as $@. | test_heuristic.rs:81:22:81:31 | MY_CONST_1 | a salt | | test_heuristic.rs:39:25:39:59 | ... as u64 | test_heuristic.rs:39:25:39:59 | ... as u64 | test_heuristic.rs:82:22:82:31 | MY_CONST_2 | This hard-coded value is used as $@. | test_heuristic.rs:82:22:82:31 | MY_CONST_2 | a salt | | test_heuristic.rs:40:27:40:32 | 0xFFFF | test_heuristic.rs:40:27:40:32 | 0xFFFF | test_heuristic.rs:83:22:83:32 | MY_STATIC_3 | This hard-coded value is used as $@. | test_heuristic.rs:83:22:83:32 | MY_STATIC_3 | a salt | @@ -28,31 +29,31 @@ edges | test_cipher.rs:18:28:18:36 | &... [&ref] | test_cipher.rs:18:9:18:14 | const1 [&ref] | provenance | | | test_cipher.rs:18:29:18:36 | [0u8; 16] | test_cipher.rs:18:28:18:36 | &... [&ref] | provenance | | | test_cipher.rs:19:49:19:79 | ...::from_slice(...) [&ref] | test_cipher.rs:19:49:19:79 | ...::from_slice(...) | provenance | Sink:MaD:2 | -| test_cipher.rs:19:73:19:78 | const1 [&ref] | test_cipher.rs:19:49:19:79 | ...::from_slice(...) [&ref] | provenance | MaD:13 | +| test_cipher.rs:19:73:19:78 | const1 [&ref] | test_cipher.rs:19:49:19:79 | ...::from_slice(...) [&ref] | provenance | MaD:14 | | test_cipher.rs:25:9:25:14 | const4 [&ref] | test_cipher.rs:26:66:26:71 | const4 [&ref] | provenance | | | test_cipher.rs:25:28:25:36 | &... [&ref] | test_cipher.rs:25:9:25:14 | const4 [&ref] | provenance | | | test_cipher.rs:25:29:25:36 | [0u8; 16] | test_cipher.rs:25:28:25:36 | &... [&ref] | provenance | | | test_cipher.rs:26:42:26:72 | ...::from_slice(...) [&ref] | test_cipher.rs:26:42:26:72 | ...::from_slice(...) | provenance | Sink:MaD:3 | -| test_cipher.rs:26:66:26:71 | const4 [&ref] | test_cipher.rs:26:42:26:72 | ...::from_slice(...) [&ref] | provenance | MaD:13 | +| test_cipher.rs:26:66:26:71 | const4 [&ref] | test_cipher.rs:26:42:26:72 | ...::from_slice(...) [&ref] | provenance | MaD:14 | | test_cipher.rs:29:9:29:14 | const5 [&ref] | test_cipher.rs:30:95:30:100 | const5 [&ref] | provenance | | | test_cipher.rs:29:28:29:36 | &... [&ref] | test_cipher.rs:29:9:29:14 | const5 [&ref] | provenance | | | test_cipher.rs:29:29:29:36 | [0u8; 16] | test_cipher.rs:29:28:29:36 | &... [&ref] | provenance | | | test_cipher.rs:30:72:30:101 | ...::from_slice(...) [&ref] | test_cipher.rs:30:72:30:101 | ...::from_slice(...) | provenance | Sink:MaD:4 | -| test_cipher.rs:30:95:30:100 | const5 [&ref] | test_cipher.rs:30:72:30:101 | ...::from_slice(...) [&ref] | provenance | MaD:13 | +| test_cipher.rs:30:95:30:100 | const5 [&ref] | test_cipher.rs:30:72:30:101 | ...::from_slice(...) [&ref] | provenance | MaD:14 | | test_cipher.rs:37:9:37:14 | const7 | test_cipher.rs:38:74:38:79 | const7 | provenance | | | test_cipher.rs:37:27:37:74 | [...] | test_cipher.rs:37:9:37:14 | const7 | provenance | | | test_cipher.rs:38:49:38:80 | ...::from_slice(...) [&ref] | test_cipher.rs:38:49:38:80 | ...::from_slice(...) | provenance | Sink:MaD:2 | -| test_cipher.rs:38:73:38:79 | &const7 [&ref] | test_cipher.rs:38:49:38:80 | ...::from_slice(...) [&ref] | provenance | MaD:13 | +| test_cipher.rs:38:73:38:79 | &const7 [&ref] | test_cipher.rs:38:49:38:80 | ...::from_slice(...) [&ref] | provenance | MaD:14 | | test_cipher.rs:38:74:38:79 | const7 | test_cipher.rs:38:73:38:79 | &const7 [&ref] | provenance | | | test_cipher.rs:41:9:41:14 | const8 [&ref] | test_cipher.rs:42:73:42:78 | const8 [&ref] | provenance | | | test_cipher.rs:41:28:41:76 | &... [&ref] | test_cipher.rs:41:9:41:14 | const8 [&ref] | provenance | | | test_cipher.rs:41:29:41:76 | [...] | test_cipher.rs:41:28:41:76 | &... [&ref] | provenance | | | test_cipher.rs:42:49:42:79 | ...::from_slice(...) [&ref] | test_cipher.rs:42:49:42:79 | ...::from_slice(...) | provenance | Sink:MaD:2 | -| test_cipher.rs:42:73:42:78 | const8 [&ref] | test_cipher.rs:42:49:42:79 | ...::from_slice(...) [&ref] | provenance | MaD:13 | +| test_cipher.rs:42:73:42:78 | const8 [&ref] | test_cipher.rs:42:49:42:79 | ...::from_slice(...) [&ref] | provenance | MaD:14 | | test_cipher.rs:50:9:50:15 | const10 [element] | test_cipher.rs:51:75:51:81 | const10 [element] | provenance | | | test_cipher.rs:50:37:50:54 | ...::zeroed(...) | test_cipher.rs:50:9:50:15 | const10 [element] | provenance | Src:MaD:7 | | test_cipher.rs:51:50:51:82 | ...::from_slice(...) [&ref, element] | test_cipher.rs:51:50:51:82 | ...::from_slice(...) | provenance | Sink:MaD:2 Sink:MaD:2 | -| test_cipher.rs:51:74:51:81 | &const10 [&ref, element] | test_cipher.rs:51:50:51:82 | ...::from_slice(...) [&ref, element] | provenance | MaD:13 | +| test_cipher.rs:51:74:51:81 | &const10 [&ref, element] | test_cipher.rs:51:50:51:82 | ...::from_slice(...) [&ref, element] | provenance | MaD:14 | | test_cipher.rs:51:75:51:81 | const10 [element] | test_cipher.rs:51:74:51:81 | &const10 [&ref, element] | provenance | | | test_cipher.rs:73:9:73:14 | const2 [&ref] | test_cipher.rs:74:46:74:51 | const2 | provenance | Sink:MaD:6 | | test_cipher.rs:73:18:73:26 | &... [&ref] | test_cipher.rs:73:9:73:14 | const2 [&ref] | provenance | | @@ -65,16 +66,20 @@ edges | test_cookie.rs:21:28:21:34 | [0; 64] | test_cookie.rs:21:9:21:14 | array2 | provenance | | | test_cookie.rs:22:26:22:32 | &array2 [&ref] | test_cookie.rs:22:26:22:32 | &array2 | provenance | Sink:MaD:5 | | test_cookie.rs:22:27:22:32 | array2 | test_cookie.rs:22:26:22:32 | &array2 [&ref] | provenance | | -| test_cookie.rs:38:9:38:14 | array2 | test_cookie.rs:42:34:42:39 | array2 | provenance | Sink:MaD:1 | -| test_cookie.rs:38:18:38:37 | ...::from(...) | test_cookie.rs:38:9:38:14 | array2 | provenance | | -| test_cookie.rs:38:28:38:36 | [0u8; 64] | test_cookie.rs:38:18:38:37 | ...::from(...) | provenance | MaD:8 | -| test_cookie.rs:38:28:38:36 | [0u8; 64] | test_cookie.rs:38:18:38:37 | ...::from(...) | provenance | MaD:9 | -| test_cookie.rs:38:28:38:36 | [0u8; 64] | test_cookie.rs:38:18:38:37 | ...::from(...) | provenance | MaD:10 | -| test_cookie.rs:38:28:38:36 | [0u8; 64] | test_cookie.rs:38:18:38:37 | ...::from(...) | provenance | MaD:11 | -| test_cookie.rs:38:28:38:36 | [0u8; 64] | test_cookie.rs:38:18:38:37 | ...::from(...) | provenance | MaD:12 | -| test_cookie.rs:49:9:49:14 | array3 [element] | test_cookie.rs:53:34:53:39 | array3 | provenance | Sink:MaD:1 | -| test_cookie.rs:49:23:49:25 | 0u8 | test_cookie.rs:49:23:49:29 | ...::from_elem(...) [element] | provenance | MaD:14 | -| test_cookie.rs:49:23:49:29 | ...::from_elem(...) [element] | test_cookie.rs:49:9:49:14 | array3 [element] | provenance | | +| test_cookie.rs:25:9:25:12 | str3 | test_cookie.rs:30:26:30:29 | str3 | provenance | | +| test_cookie.rs:25:16:29:5 | match ... { ... } | test_cookie.rs:25:9:25:12 | str3 | provenance | | +| test_cookie.rs:30:26:30:29 | str3 | test_cookie.rs:30:26:30:40 | str3.as_bytes() [&ref] | provenance | MaD:13 | +| test_cookie.rs:30:26:30:40 | str3.as_bytes() [&ref] | test_cookie.rs:30:26:30:40 | str3.as_bytes() | provenance | Sink:MaD:5 | +| test_cookie.rs:46:9:46:14 | array2 | test_cookie.rs:50:34:50:39 | array2 | provenance | Sink:MaD:1 | +| test_cookie.rs:46:18:46:37 | ...::from(...) | test_cookie.rs:46:9:46:14 | array2 | provenance | | +| test_cookie.rs:46:28:46:36 | [0u8; 64] | test_cookie.rs:46:18:46:37 | ...::from(...) | provenance | MaD:8 | +| test_cookie.rs:46:28:46:36 | [0u8; 64] | test_cookie.rs:46:18:46:37 | ...::from(...) | provenance | MaD:9 | +| test_cookie.rs:46:28:46:36 | [0u8; 64] | test_cookie.rs:46:18:46:37 | ...::from(...) | provenance | MaD:10 | +| test_cookie.rs:46:28:46:36 | [0u8; 64] | test_cookie.rs:46:18:46:37 | ...::from(...) | provenance | MaD:11 | +| test_cookie.rs:46:28:46:36 | [0u8; 64] | test_cookie.rs:46:18:46:37 | ...::from(...) | provenance | MaD:12 | +| test_cookie.rs:57:9:57:14 | array3 [element] | test_cookie.rs:61:34:61:39 | array3 | provenance | Sink:MaD:1 | +| test_cookie.rs:57:23:57:25 | 0u8 | test_cookie.rs:57:23:57:29 | ...::from_elem(...) [element] | provenance | MaD:15 | +| test_cookie.rs:57:23:57:29 | ...::from_elem(...) [element] | test_cookie.rs:57:9:57:14 | array3 [element] | provenance | | | test_heuristic.rs:38:25:38:30 | 0xFFFF | test_heuristic.rs:81:22:81:31 | MY_CONST_1 | provenance | | | test_heuristic.rs:39:25:39:59 | ... as u64 | test_heuristic.rs:82:22:82:31 | MY_CONST_2 | provenance | | | test_heuristic.rs:39:62:40:33 | static MY_STATIC_3 | test_heuristic.rs:83:22:83:32 | MY_STATIC_3 | provenance | | @@ -99,8 +104,9 @@ models | 10 | Summary: ::from; Argument[0].Field[alloc::collections::binary_heap::BinaryHeap::data]; ReturnValue; value | | 11 | Summary: ::from; Argument[0].Field[alloc::string::String::vec]; ReturnValue; value | | 12 | Summary: ::from; Argument[0]; ReturnValue; taint | -| 13 | Summary: ::from_slice; Argument[0].Reference; ReturnValue.Reference; value | -| 14 | Summary: alloc::vec::from_elem; Argument[0]; ReturnValue.Element; value | +| 13 | Summary: ::as_bytes; Argument[self].Reference; ReturnValue.Reference; taint | +| 14 | Summary: ::from_slice; Argument[0].Reference; ReturnValue.Reference; value | +| 15 | Summary: alloc::vec::from_elem; Argument[0]; ReturnValue.Element; value | nodes | test_cipher.rs:18:9:18:14 | const1 [&ref] | semmle.label | const1 [&ref] | | test_cipher.rs:18:28:18:36 | &... [&ref] | semmle.label | &... [&ref] | @@ -152,14 +158,19 @@ nodes | test_cookie.rs:22:26:22:32 | &array2 | semmle.label | &array2 | | test_cookie.rs:22:26:22:32 | &array2 [&ref] | semmle.label | &array2 [&ref] | | test_cookie.rs:22:27:22:32 | array2 | semmle.label | array2 | -| test_cookie.rs:38:9:38:14 | array2 | semmle.label | array2 | -| test_cookie.rs:38:18:38:37 | ...::from(...) | semmle.label | ...::from(...) | -| test_cookie.rs:38:28:38:36 | [0u8; 64] | semmle.label | [0u8; 64] | -| test_cookie.rs:42:34:42:39 | array2 | semmle.label | array2 | -| test_cookie.rs:49:9:49:14 | array3 [element] | semmle.label | array3 [element] | -| test_cookie.rs:49:23:49:25 | 0u8 | semmle.label | 0u8 | -| test_cookie.rs:49:23:49:29 | ...::from_elem(...) [element] | semmle.label | ...::from_elem(...) [element] | -| test_cookie.rs:53:34:53:39 | array3 | semmle.label | array3 | +| test_cookie.rs:25:9:25:12 | str3 | semmle.label | str3 | +| test_cookie.rs:25:16:29:5 | match ... { ... } | semmle.label | match ... { ... } | +| test_cookie.rs:30:26:30:29 | str3 | semmle.label | str3 | +| test_cookie.rs:30:26:30:40 | str3.as_bytes() | semmle.label | str3.as_bytes() | +| test_cookie.rs:30:26:30:40 | str3.as_bytes() [&ref] | semmle.label | str3.as_bytes() [&ref] | +| test_cookie.rs:46:9:46:14 | array2 | semmle.label | array2 | +| test_cookie.rs:46:18:46:37 | ...::from(...) | semmle.label | ...::from(...) | +| test_cookie.rs:46:28:46:36 | [0u8; 64] | semmle.label | [0u8; 64] | +| test_cookie.rs:50:34:50:39 | array2 | semmle.label | array2 | +| test_cookie.rs:57:9:57:14 | array3 [element] | semmle.label | array3 [element] | +| test_cookie.rs:57:23:57:25 | 0u8 | semmle.label | 0u8 | +| test_cookie.rs:57:23:57:29 | ...::from_elem(...) [element] | semmle.label | ...::from_elem(...) [element] | +| test_cookie.rs:61:34:61:39 | array3 | semmle.label | array3 | | test_heuristic.rs:38:25:38:30 | 0xFFFF | semmle.label | 0xFFFF | | test_heuristic.rs:39:25:39:59 | ... as u64 | semmle.label | ... as u64 | | test_heuristic.rs:39:62:40:33 | static MY_STATIC_3 | semmle.label | static MY_STATIC_3 | diff --git a/rust/ql/test/query-tests/security/CWE-798/test_cookie.rs b/rust/ql/test/query-tests/security/CWE-798/test_cookie.rs index 10852583c678..410ddf1b8aaa 100644 --- a/rust/ql/test/query-tests/security/CWE-798/test_cookie.rs +++ b/rust/ql/test/query-tests/security/CWE-798/test_cookie.rs @@ -3,7 +3,7 @@ use cookie::{CookieJar, SignedJar, PrivateJar, Key}; // --- tests --- -fn test_cookie_jar(array_var: &[u8]) { +fn test_cookie_jar(array_var: &[u8], val: u64) { let mut jar = CookieJar::new(); let key_generate = Key::generate(); // good @@ -21,6 +21,14 @@ fn test_cookie_jar(array_var: &[u8]) { let array2: [u8; 64] = [0; 64]; // $ Alert[rust/hard-coded-cryptographic-value] let key2 = Key::from(&array2); // $ Sink _ = jar.private_mut(&key2); + + let str3 = match(val) { + 0 => "one", + 1 => "two", + _ => "many" + }; // $ Alert[rust/hard-coded-cryptographic-value] + let key3 = Key::from(str3.as_bytes()); // $ Sink + _ = jar.signed_mut(&key3); } fn test_biscotti_crypto(array_var: &[u8]) {