Rust: Query for cleartext logging of sensitive information#18582
Rust: Query for cleartext logging of sensitive information#18582geoffw0 merged 22 commits intogithub:mainfrom
Conversation
There was a problem hiding this comment.
Copilot reviewed 13 out of 13 changed files in this pull request and generated 1 comment.
Tip: If you use Visual Studio Code, you can request a review from Copilot before you push from the "Source Control" tab. Learn more
|
|
||
| predicate isAdditionalFlowStep(Node node1, Node node2) { | ||
| // flow from `a` to `&a` | ||
| node2.asExpr().getExpr().(RefExpr).getExpr() = node1.asExpr().getExpr() |
There was a problem hiding this comment.
We possibly want something like this as a general flow step. It matters for basically all the test cases that mention &password in the source I think. @paldepind what do you think?
There was a problem hiding this comment.
Agree that adding this as an additional flow step shouldn't be necessary.
I actually would've thought that this should work. If password is tainted then &password should have taint stored in the reference and this implicit read step at the sink should ensure that it is read. I can look into it and see why it doesn't work.
There was a problem hiding this comment.
Yes, please do look into this, it looks like it should work to me as well.
There was a problem hiding this comment.
I've written up an issue for this as I think it's worth investigating and there are definitely some improvements we can make.
| predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) { | ||
| // flow out from tuple content at sinks. | ||
| isSink(node) and | ||
| c.getAReadContent() instanceof TuplePositionContent |
There was a problem hiding this comment.
I couldn't get tuple content to work in the models-as-data sink itself, so this might have to do for now.
There was a problem hiding this comment.
The Tuple[i] notation should work for summaries (there's a test here). But I'm not sure if it's also expected to work for sinks.
There was a problem hiding this comment.
I tried the Tuple[i] notation and couldn't get it to work. I'm not sure I could've messed up the syntax, it's pretty simple. So best guess, it doesn't work on sinks at the moment???
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
|
QHelp previews: rust/ql/src/queries/security/CWE-312/CleartextLogging.qhelpCleartext logging of sensitive informationSensitive user data and system information that is logged could be exposed to an attacker when it is displayed. Also, external processes often store the standard output and standard error streams of an application, which will include logged sensitive information. RecommendationDo not log sensitive data. If it is necessary to log sensitive data, encrypt it before logging. ExampleThe following example code logs user credentials (in this case, their password) in plaintext: let password = "P@ssw0rd";
info!("User password changed to {password}");Instead, you should encrypt the credentials, or better still, omit them entirely: let password = "P@ssw0rd";
info!("User password changed");References
|
| predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) { | ||
| // flow out from tuple content at sinks. | ||
| isSink(node) and | ||
| c.getAReadContent() instanceof TuplePositionContent |
There was a problem hiding this comment.
The Tuple[i] notation should work for summaries (there's a test here). But I'm not sure if it's also expected to work for sinks.
|
|
||
| predicate isAdditionalFlowStep(Node node1, Node node2) { | ||
| // flow from `a` to `&a` | ||
| node2.asExpr().getExpr().(RefExpr).getExpr() = node1.asExpr().getExpr() |
There was a problem hiding this comment.
Agree that adding this as an additional flow step shouldn't be necessary.
I actually would've thought that this should work. If password is tainted then &password should have taint stored in the reference and this implicit read step at the sink should ensure that it is read. I can look into it and see why it doesn't work.
| @@ -0,0 +1,3 @@ | |||
| extractionWarning | |||
| | test_logging.rs:90:12:90:30 | expected R_PAREN | | |||
| | test_logging.rs:90:12:90:30 | macro expansion failed: the macro '$crate::__private_api::format_args' expands to ERROR but a Expr was expected | No newline at end of file | |||
There was a problem hiding this comment.
Looks like there's an error on line 90. Maybe it's the :?? I'm not familiar with the error! macro.
There was a problem hiding this comment.
Ah, I had assumed this must be an extractor bug, but I never actually ran rustc on this code...
There was a problem hiding this comment.
I've made the test runnable, and ran it. The syntax on line 90 is accepted by the compiler and produces the expected output (well, I think SimpleLogger is discarding the keys / values / structured part, presumably a more sophisticated logger would use it).
There was a problem hiding this comment.
I see. Maybe it's because the key-value syntax requires the kv feature to be turned on, but the extractor always uses the default features.
There was a problem hiding this comment.
Sounds like there's nothing wrong with the test then (it does turn the kv feature on). This probably explains why I couldn't get the results on lines 77 and 78 (which use the kv feature).
There was a problem hiding this comment.
Yes, I think you're right :)
mchammer01
left a comment
There was a problem hiding this comment.
LGTM from a Docs perspective ✨
Added two minor suggestions for your consideration.
|
DCA shows 19 query results:
I'll address the clear FPs in a follow-up, since they're all shortcomings in the (shared) sensitive data heuristics. |
New query for cleartext logging of sensitive information in Rust. There are plans to add more sinks in future, but what's here should give us fairly good coverage.