Merge pull request #19000 from paldepind/rust-cleartext-transmission

Rust: Add cleartext transmission query
This commit is contained in:
Simon Friis Vindum
2025-03-17 14:56:57 +01:00
committed by GitHub
13 changed files with 362 additions and 4 deletions

View File

@@ -5,6 +5,12 @@ extensions:
data:
- ["repo:https://github.com/seanmonstar/reqwest:reqwest", "crate::get", "ReturnValue.Field[crate::result::Result::Ok(0)]", "remote", "manual"]
- ["repo:https://github.com/seanmonstar/reqwest:reqwest", "crate::blocking::get", "ReturnValue.Field[crate::result::Result::Ok(0)]", "remote", "manual"]
- addsTo:
pack: codeql/rust-all
extensible: sinkModel
data:
- ["repo:https://github.com/seanmonstar/reqwest:reqwest", "<crate::async_impl::client::Client>::request", "Argument[1]", "transmission", "manual"]
- ["repo:https://github.com/seanmonstar/reqwest:reqwest", "<crate::blocking::client::Client>::request", "Argument[1]", "transmission", "manual"]
- addsTo:
pack: codeql/rust-all
extensible: summaryModel

View File

@@ -0,0 +1,7 @@
# Models for the `url` crate
extensions:
- addsTo:
pack: codeql/rust-all
extensible: summaryModel
data:
- ["repo:https://github.com/servo/rust-url:url", "<crate::Url>::parse", "Argument[0].Reference", "ReturnValue.Field[crate::result::Result::Ok(0)]", "taint", "manual"]

View File

@@ -0,0 +1,38 @@
/**
* Provides classes and predicates for reasoning about cleartext transmission
* vulnerabilities.
*/
private import codeql.util.Unit
private import rust
private import codeql.rust.dataflow.DataFlow
private import codeql.rust.dataflow.FlowSink
/**
* A data flow sink for cleartext transmission vulnerabilities. That is,
* a `DataFlow::Node` of something that is transmitted over a network.
*/
abstract class CleartextTransmissionSink extends DataFlow::Node { }
/**
* A barrier for cleartext transmission vulnerabilities.
*/
abstract class CleartextTransmissionBarrier extends DataFlow::Node { }
/**
* A unit class for adding additional flow steps.
*/
class CleartextTransmissionAdditionalFlowStep extends Unit {
/**
* Holds if the step from `node1` to `node2` should be considered a flow
* step for paths related to cleartext transmission vulnerabilities.
*/
abstract predicate step(DataFlow::Node nodeFrom, DataFlow::Node nodeTo);
}
/**
* A sink defined through MaD.
*/
private class MadCleartextTransmissionSink extends CleartextTransmissionSink {
MadCleartextTransmissionSink() { sinkNode(this, "transmission") }
}

View File

@@ -0,0 +1,23 @@
# THIS FILE IS AN AUTO-GENERATED MODELS AS DATA FILE. DO NOT EDIT.
extensions:
- addsTo:
pack: codeql/rust-all
extensible: sinkModel
data:
- ["repo:https://github.com/seanmonstar/reqwest:reqwest", "<crate::async_impl::client::Client>::delete", "Argument[0]", "transmission", "df-generated"]
- ["repo:https://github.com/seanmonstar/reqwest:reqwest", "<crate::async_impl::client::Client>::get", "Argument[0]", "transmission", "df-generated"]
- ["repo:https://github.com/seanmonstar/reqwest:reqwest", "<crate::async_impl::client::Client>::head", "Argument[0]", "transmission", "df-generated"]
- ["repo:https://github.com/seanmonstar/reqwest:reqwest", "<crate::async_impl::client::Client>::patch", "Argument[0]", "transmission", "df-generated"]
- ["repo:https://github.com/seanmonstar/reqwest:reqwest", "<crate::async_impl::client::Client>::post", "Argument[0]", "transmission", "df-generated"]
- ["repo:https://github.com/seanmonstar/reqwest:reqwest", "<crate::async_impl::client::Client>::put", "Argument[0]", "transmission", "df-generated"]
- ["repo:https://github.com/seanmonstar/reqwest:reqwest", "<crate::blocking::client::Client>::delete", "Argument[0]", "transmission", "df-generated"]
- ["repo:https://github.com/seanmonstar/reqwest:reqwest", "<crate::blocking::client::Client>::get", "Argument[0]", "transmission", "df-generated"]
- ["repo:https://github.com/seanmonstar/reqwest:reqwest", "<crate::blocking::client::Client>::head", "Argument[0]", "transmission", "df-generated"]
- ["repo:https://github.com/seanmonstar/reqwest:reqwest", "<crate::blocking::client::Client>::patch", "Argument[0]", "transmission", "df-generated"]
- ["repo:https://github.com/seanmonstar/reqwest:reqwest", "<crate::blocking::client::Client>::post", "Argument[0]", "transmission", "df-generated"]
- ["repo:https://github.com/seanmonstar/reqwest:reqwest", "<crate::blocking::client::Client>::put", "Argument[0]", "transmission", "df-generated"]
- ["repo:https://github.com/seanmonstar/reqwest:reqwest", "<crate::connect::Connector as crate::Service>::call", "Argument[0]", "log-injection", "df-generated"]
- ["repo:https://github.com/seanmonstar/reqwest:reqwest", "<crate::connect::ConnectorService as crate::Service>::call", "Argument[0]", "log-injection", "df-generated"]
- ["repo:https://github.com/seanmonstar/reqwest:reqwest", "crate::blocking::get", "Argument[0]", "transmission", "df-generated"]
- ["repo:https://github.com/seanmonstar/reqwest:reqwest", "crate::blocking::wait::timeout", "Argument[1]", "log-injection", "df-generated"]
- ["repo:https://github.com/seanmonstar/reqwest:reqwest", "crate::get", "Argument[0]", "transmission", "df-generated"]

View File

@@ -0,0 +1,51 @@
<!DOCTYPE qhelp PUBLIC "-//Semmle//qhelp//EN" "qhelp.dtd">
<qhelp>
<overview>
<p>
Sensitive information that is transmitted without encryption may be accessible
to an attacker.
</p>
</overview>
<recommendation>
<p>
Ensure that sensitive information is always encrypted before being transmitted
over the network. In general, decrypt sensitive information only at the point
where it is necessary for it to be used in cleartext. Avoid transmitting
sensitive information when it is not necessary to.
</p>
</recommendation>
<example>
<p>
The following example shows three cases of transmitting information. In the
'BAD' case, the transmitted data is sensitive (a credit card number) and is
included as cleartext in the URL. URLs are often logged or otherwise visible in
cleartext, and should not contain sensitive information.
</p>
<p>
In the 'GOOD' cases, the data is either not sensitive, or is protected with
encryption. When encryption is used, ensure that you select a secure modern
encryption algorithm, and put suitable key management practices into place.
</p>
<sample src="CleartextTransmission.rs" />
</example>
<references>
<li>
OWASP Top 10:2021:
<a href="https://owasp.org/Top10/A02_2021-Cryptographic_Failures/">A02:2021 - Cryptographic Failures</a>.
</li>
<li>
OWASP:
<a href="https://cheatsheetseries.owasp.org/cheatsheets/Key_Management_Cheat_Sheet.html">Key Management Cheat Sheet</a>.
</li>
</references>
</qhelp>

View File

@@ -0,0 +1,50 @@
/**
* @name Cleartext transmission of sensitive information
* @description Transmitting sensitive information across a network in
* cleartext can expose it to an attacker.
* @kind path-problem
* @problem.severity warning
* @security-severity 7.5
* @precision high
* @id rust/cleartext-transmission
* @tags security
* external/cwe/cwe-319
*/
import rust
import codeql.rust.dataflow.DataFlow
import codeql.rust.security.SensitiveData
import codeql.rust.dataflow.TaintTracking
import codeql.rust.security.CleartextTransmissionExtensions
/**
* A taint configuration from sensitive information to expressions that are
* transmitted over a network.
*/
module CleartextTransmissionConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node node) { node instanceof SensitiveData }
predicate isSink(DataFlow::Node node) { node instanceof CleartextTransmissionSink }
predicate isBarrier(DataFlow::Node barrier) { barrier instanceof CleartextTransmissionBarrier }
predicate isAdditionalFlowStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
any(CleartextTransmissionAdditionalFlowStep s).step(nodeFrom, nodeTo)
}
predicate isBarrierIn(DataFlow::Node node) {
// make sources barriers so that we only report the closest instance
isSource(node)
}
}
module CleartextTransmissionFlow = TaintTracking::Global<CleartextTransmissionConfig>;
import CleartextTransmissionFlow::PathGraph
from CleartextTransmissionFlow::PathNode sourceNode, CleartextTransmissionFlow::PathNode sinkNode
where CleartextTransmissionFlow::flowPath(sourceNode, sinkNode)
select sinkNode.getNode(), sourceNode, sinkNode,
"The operation '" + sinkNode.getNode().toString() +
"', transmits data which may contain unencrypted sensitive data from $@.", sourceNode,
sourceNode.getNode().toString()

View File

@@ -0,0 +1,15 @@
func getData() {
// ...
// GOOD: not sensitive information
let body = reqwest::get("https://example.com/song/{faveSong}").await?.text().await?;
// BAD: sensitive information sent in cleartext in the URL
let body = reqwest::get(format!("https://example.com/card/{creditCardNo}")).await?.text().await?;
// GOOD: encrypted sensitive information sent in the URL
let encryptedPassword = encrypt(password, encryptionKey);
let body = reqwest::get(format!("https://example.com/card/{creditCardNo}")).await?.text().await?;
// ...
}

View File

@@ -2216,6 +2216,7 @@ storeStep
| file://:0:0:0:0 | [summary] to write: ReturnValue.Field[crate::result::Result::Ok(0)] in repo:https://github.com/seanmonstar/reqwest:reqwest::_::<crate::response::Response>::chunk | Ok | file://:0:0:0:0 | [summary] to write: ReturnValue in repo:https://github.com/seanmonstar/reqwest:reqwest::_::<crate::response::Response>::chunk |
| file://:0:0:0:0 | [summary] to write: ReturnValue.Field[crate::result::Result::Ok(0)] in repo:https://github.com/seanmonstar/reqwest:reqwest::_::<crate::response::Response>::text | Ok | file://:0:0:0:0 | [summary] to write: ReturnValue in repo:https://github.com/seanmonstar/reqwest:reqwest::_::<crate::response::Response>::text |
| file://:0:0:0:0 | [summary] to write: ReturnValue.Field[crate::result::Result::Ok(0)] in repo:https://github.com/seanmonstar/reqwest:reqwest::_::<crate::response::Response>::text_with_charset | Ok | file://:0:0:0:0 | [summary] to write: ReturnValue in repo:https://github.com/seanmonstar/reqwest:reqwest::_::<crate::response::Response>::text_with_charset |
| file://:0:0:0:0 | [summary] to write: ReturnValue.Field[crate::result::Result::Ok(0)] in repo:https://github.com/servo/rust-url:url::_::<crate::Url>::parse | Ok | file://:0:0:0:0 | [summary] to write: ReturnValue in repo:https://github.com/servo/rust-url:url::_::<crate::Url>::parse |
| file://:0:0:0:0 | [summary] to write: ReturnValue.Field[crate::result::Result::Ok(0)].Field[0] in lang:alloc::_::<crate::collections::btree::node::NodeRef>::search_tree_for_bifurcation | tuple.0 | file://:0:0:0:0 | [summary] to write: ReturnValue.Field[crate::result::Result::Ok(0)] in lang:alloc::_::<crate::collections::btree::node::NodeRef>::search_tree_for_bifurcation |
| file://:0:0:0:0 | [summary] to write: ReturnValue.Field[crate::result::Result::Ok(0)].Field[0] in lang:std::_::<crate::sync::poison::condvar::Condvar>::wait_timeout | tuple.0 | file://:0:0:0:0 | [summary] to write: ReturnValue.Field[crate::result::Result::Ok(0)] in lang:std::_::<crate::sync::poison::condvar::Condvar>::wait_timeout |
| file://:0:0:0:0 | [summary] to write: ReturnValue.Field[crate::result::Result::Ok(0)].Field[0] in lang:std::_::<crate::sync::poison::condvar::Condvar>::wait_timeout_ms | tuple.0 | file://:0:0:0:0 | [summary] to write: ReturnValue.Field[crate::result::Result::Ok(0)] in lang:std::_::<crate::sync::poison::condvar::Condvar>::wait_timeout_ms |
@@ -2495,6 +2496,7 @@ readStep
| file://:0:0:0:0 | [summary param] 0 in lang:std::_::crate::thread::current::try_with_current | function return | file://:0:0:0:0 | [summary] read: Argument[0].ReturnValue in lang:std::_::crate::thread::current::try_with_current |
| file://:0:0:0:0 | [summary param] 0 in lang:std::_::crate::thread::with_current_name | function return | file://:0:0:0:0 | [summary] read: Argument[0].ReturnValue in lang:std::_::crate::thread::with_current_name |
| file://:0:0:0:0 | [summary param] 0 in repo:https://github.com/rust-lang/regex:regex::_::crate::escape | &ref | file://:0:0:0:0 | [summary] read: Argument[0].Reference in repo:https://github.com/rust-lang/regex:regex::_::crate::escape |
| file://:0:0:0:0 | [summary param] 0 in repo:https://github.com/servo/rust-url:url::_::<crate::Url>::parse | &ref | file://:0:0:0:0 | [summary] read: Argument[0].Reference in repo:https://github.com/servo/rust-url:url::_::<crate::Url>::parse |
| file://:0:0:0:0 | [summary param] 1 in lang:alloc::_::<crate::vec::into_iter::IntoIter as crate::iter::traits::iterator::Iterator>::fold | function return | file://:0:0:0:0 | [summary] read: Argument[1].ReturnValue in lang:alloc::_::<crate::vec::into_iter::IntoIter as crate::iter::traits::iterator::Iterator>::fold |
| file://:0:0:0:0 | [summary param] 1 in lang:alloc::_::crate::collections::btree::mem::replace | function return | file://:0:0:0:0 | [summary] read: Argument[1].ReturnValue in lang:alloc::_::crate::collections::btree::mem::replace |
| file://:0:0:0:0 | [summary param] 1 in lang:alloc::_::crate::collections::btree::mem::take_mut | function return | file://:0:0:0:0 | [summary] read: Argument[1].ReturnValue in lang:alloc::_::crate::collections::btree::mem::take_mut |

View File

@@ -2,15 +2,15 @@
| main.rs:6:25:6:30 | &regex | main.rs:4:20:4:32 | ...::var | main.rs:6:25:6:30 | &regex | This regular expression is constructed from a $@. | main.rs:4:20:4:32 | ...::var | user-provided value |
edges
| main.rs:4:9:4:16 | username | main.rs:5:25:5:44 | MacroExpr | provenance | |
| main.rs:4:20:4:32 | ...::var | main.rs:4:20:4:40 | ...::var(...) [Ok] | provenance | Src:MaD:60 |
| main.rs:4:20:4:40 | ...::var(...) [Ok] | main.rs:4:20:4:66 | ... .unwrap_or(...) | provenance | MaD:1573 |
| main.rs:4:20:4:32 | ...::var | main.rs:4:20:4:40 | ...::var(...) [Ok] | provenance | Src:MaD:62 |
| main.rs:4:20:4:40 | ...::var(...) [Ok] | main.rs:4:20:4:66 | ... .unwrap_or(...) | provenance | MaD:1593 |
| main.rs:4:20:4:66 | ... .unwrap_or(...) | main.rs:4:9:4:16 | username | provenance | |
| main.rs:5:9:5:13 | regex | main.rs:6:26:6:30 | regex | provenance | |
| main.rs:5:17:5:45 | res | main.rs:5:25:5:44 | { ... } | provenance | |
| main.rs:5:25:5:44 | ...::format(...) | main.rs:5:17:5:45 | res | provenance | |
| main.rs:5:25:5:44 | ...::must_use(...) | main.rs:5:9:5:13 | regex | provenance | |
| main.rs:5:25:5:44 | MacroExpr | main.rs:5:25:5:44 | ...::format(...) | provenance | MaD:64 |
| main.rs:5:25:5:44 | { ... } | main.rs:5:25:5:44 | ...::must_use(...) | provenance | MaD:2996 |
| main.rs:5:25:5:44 | MacroExpr | main.rs:5:25:5:44 | ...::format(...) | provenance | MaD:66 |
| main.rs:5:25:5:44 | { ... } | main.rs:5:25:5:44 | ...::must_use(...) | provenance | MaD:3016 |
| main.rs:6:26:6:30 | regex | main.rs:6:25:6:30 | &regex | provenance | |
nodes
| main.rs:4:9:4:16 | username | semmle.label | username |

View File

@@ -0,0 +1,113 @@
#select
| main.rs:7:5:7:26 | ...::get | main.rs:6:50:6:57 | password | main.rs:7:5:7:26 | ...::get | The operation '...::get', transmits data which may contain unencrypted sensitive data from $@. | main.rs:6:50:6:57 | password | password |
| main.rs:14:5:14:26 | ...::get | main.rs:12:50:12:57 | password | main.rs:14:5:14:26 | ...::get | The operation '...::get', transmits data which may contain unencrypted sensitive data from $@. | main.rs:12:50:12:57 | password | password |
| main.rs:21:12:21:15 | post | main.rs:19:50:19:57 | password | main.rs:21:12:21:15 | post | The operation 'post', transmits data which may contain unencrypted sensitive data from $@. | main.rs:19:50:19:57 | password | password |
| main.rs:28:12:28:18 | request | main.rs:26:50:26:57 | password | main.rs:28:12:28:18 | request | The operation 'request', transmits data which may contain unencrypted sensitive data from $@. | main.rs:26:50:26:57 | password | password |
| main.rs:35:12:35:18 | request | main.rs:33:50:33:57 | password | main.rs:35:12:35:18 | request | The operation 'request', transmits data which may contain unencrypted sensitive data from $@. | main.rs:33:50:33:57 | password | password |
edges
| main.rs:6:9:6:11 | url | main.rs:7:28:7:30 | url | provenance | |
| main.rs:6:15:6:58 | res | main.rs:6:23:6:57 | { ... } | provenance | |
| main.rs:6:23:6:57 | ...::format(...) | main.rs:6:15:6:58 | res | provenance | |
| main.rs:6:23:6:57 | ...::must_use(...) | main.rs:6:9:6:11 | url | provenance | |
| main.rs:6:23:6:57 | MacroExpr | main.rs:6:23:6:57 | ...::format(...) | provenance | MaD:5 |
| main.rs:6:23:6:57 | { ... } | main.rs:6:23:6:57 | ...::must_use(...) | provenance | MaD:7 |
| main.rs:6:50:6:57 | password | main.rs:6:23:6:57 | MacroExpr | provenance | |
| main.rs:7:28:7:30 | url | main.rs:7:5:7:26 | ...::get | provenance | MaD:4 Sink:MaD:4 |
| main.rs:12:9:12:15 | address | main.rs:13:27:13:33 | address | provenance | |
| main.rs:12:19:12:60 | res | main.rs:12:27:12:59 | { ... } | provenance | |
| main.rs:12:27:12:59 | ...::format(...) | main.rs:12:19:12:60 | res | provenance | |
| main.rs:12:27:12:59 | ...::must_use(...) | main.rs:12:9:12:15 | address | provenance | |
| main.rs:12:27:12:59 | MacroExpr | main.rs:12:27:12:59 | ...::format(...) | provenance | MaD:5 |
| main.rs:12:27:12:59 | { ... } | main.rs:12:27:12:59 | ...::must_use(...) | provenance | MaD:7 |
| main.rs:12:50:12:57 | password | main.rs:12:27:12:59 | MacroExpr | provenance | |
| main.rs:13:9:13:11 | url | main.rs:14:28:14:30 | url | provenance | |
| main.rs:13:15:13:34 | ...::parse(...) [Ok] | main.rs:13:15:13:43 | ... .unwrap(...) | provenance | MaD:6 |
| main.rs:13:15:13:43 | ... .unwrap(...) | main.rs:13:9:13:11 | url | provenance | |
| main.rs:13:26:13:33 | &address [&ref] | main.rs:13:15:13:34 | ...::parse(...) [Ok] | provenance | MaD:8 |
| main.rs:13:27:13:33 | address | main.rs:13:26:13:33 | &address [&ref] | provenance | |
| main.rs:14:28:14:30 | url | main.rs:14:5:14:26 | ...::get | provenance | MaD:4 Sink:MaD:4 |
| main.rs:19:9:19:11 | url | main.rs:21:17:21:19 | url | provenance | |
| main.rs:19:15:19:58 | res | main.rs:19:23:19:57 | { ... } | provenance | |
| main.rs:19:23:19:57 | ...::format(...) | main.rs:19:15:19:58 | res | provenance | |
| main.rs:19:23:19:57 | ...::must_use(...) | main.rs:19:9:19:11 | url | provenance | |
| main.rs:19:23:19:57 | MacroExpr | main.rs:19:23:19:57 | ...::format(...) | provenance | MaD:5 |
| main.rs:19:23:19:57 | { ... } | main.rs:19:23:19:57 | ...::must_use(...) | provenance | MaD:7 |
| main.rs:19:50:19:57 | password | main.rs:19:23:19:57 | MacroExpr | provenance | |
| main.rs:21:17:21:19 | url | main.rs:21:12:21:15 | post | provenance | MaD:1 Sink:MaD:1 |
| main.rs:26:9:26:11 | url | main.rs:28:33:28:35 | url | provenance | |
| main.rs:26:15:26:58 | res | main.rs:26:23:26:57 | { ... } | provenance | |
| main.rs:26:23:26:57 | ...::format(...) | main.rs:26:15:26:58 | res | provenance | |
| main.rs:26:23:26:57 | ...::must_use(...) | main.rs:26:9:26:11 | url | provenance | |
| main.rs:26:23:26:57 | MacroExpr | main.rs:26:23:26:57 | ...::format(...) | provenance | MaD:5 |
| main.rs:26:23:26:57 | { ... } | main.rs:26:23:26:57 | ...::must_use(...) | provenance | MaD:7 |
| main.rs:26:50:26:57 | password | main.rs:26:23:26:57 | MacroExpr | provenance | |
| main.rs:28:33:28:35 | url | main.rs:28:12:28:18 | request | provenance | MaD:3 Sink:MaD:3 |
| main.rs:33:9:33:11 | url | main.rs:35:33:35:35 | url | provenance | |
| main.rs:33:15:33:58 | res | main.rs:33:23:33:57 | { ... } | provenance | |
| main.rs:33:23:33:57 | ...::format(...) | main.rs:33:15:33:58 | res | provenance | |
| main.rs:33:23:33:57 | ...::must_use(...) | main.rs:33:9:33:11 | url | provenance | |
| main.rs:33:23:33:57 | MacroExpr | main.rs:33:23:33:57 | ...::format(...) | provenance | MaD:5 |
| main.rs:33:23:33:57 | { ... } | main.rs:33:23:33:57 | ...::must_use(...) | provenance | MaD:7 |
| main.rs:33:50:33:57 | password | main.rs:33:23:33:57 | MacroExpr | provenance | |
| main.rs:35:33:35:35 | url | main.rs:35:12:35:18 | request | provenance | MaD:2 Sink:MaD:2 |
models
| 1 | Sink: repo:https://github.com/seanmonstar/reqwest:reqwest; <crate::async_impl::client::Client>::post; transmission; Argument[0] |
| 2 | Sink: repo:https://github.com/seanmonstar/reqwest:reqwest; <crate::async_impl::client::Client>::request; transmission; Argument[1] |
| 3 | Sink: repo:https://github.com/seanmonstar/reqwest:reqwest; <crate::blocking::client::Client>::request; transmission; Argument[1] |
| 4 | Sink: repo:https://github.com/seanmonstar/reqwest:reqwest; crate::blocking::get; transmission; Argument[0] |
| 5 | Summary: lang:alloc; crate::fmt::format; Argument[0]; ReturnValue; taint |
| 6 | Summary: lang:core; <crate::result::Result>::unwrap; Argument[self].Field[crate::result::Result::Ok(0)]; ReturnValue; value |
| 7 | Summary: lang:core; crate::hint::must_use; Argument[0]; ReturnValue; value |
| 8 | Summary: repo:https://github.com/servo/rust-url:url; <crate::Url>::parse; Argument[0].Reference; ReturnValue.Field[crate::result::Result::Ok(0)]; taint |
nodes
| main.rs:6:9:6:11 | url | semmle.label | url |
| main.rs:6:15:6:58 | res | semmle.label | res |
| main.rs:6:23:6:57 | ...::format(...) | semmle.label | ...::format(...) |
| main.rs:6:23:6:57 | ...::must_use(...) | semmle.label | ...::must_use(...) |
| main.rs:6:23:6:57 | MacroExpr | semmle.label | MacroExpr |
| main.rs:6:23:6:57 | { ... } | semmle.label | { ... } |
| main.rs:6:50:6:57 | password | semmle.label | password |
| main.rs:7:5:7:26 | ...::get | semmle.label | ...::get |
| main.rs:7:28:7:30 | url | semmle.label | url |
| main.rs:12:9:12:15 | address | semmle.label | address |
| main.rs:12:19:12:60 | res | semmle.label | res |
| main.rs:12:27:12:59 | ...::format(...) | semmle.label | ...::format(...) |
| main.rs:12:27:12:59 | ...::must_use(...) | semmle.label | ...::must_use(...) |
| main.rs:12:27:12:59 | MacroExpr | semmle.label | MacroExpr |
| main.rs:12:27:12:59 | { ... } | semmle.label | { ... } |
| main.rs:12:50:12:57 | password | semmle.label | password |
| main.rs:13:9:13:11 | url | semmle.label | url |
| main.rs:13:15:13:34 | ...::parse(...) [Ok] | semmle.label | ...::parse(...) [Ok] |
| main.rs:13:15:13:43 | ... .unwrap(...) | semmle.label | ... .unwrap(...) |
| main.rs:13:26:13:33 | &address [&ref] | semmle.label | &address [&ref] |
| main.rs:13:27:13:33 | address | semmle.label | address |
| main.rs:14:5:14:26 | ...::get | semmle.label | ...::get |
| main.rs:14:28:14:30 | url | semmle.label | url |
| main.rs:19:9:19:11 | url | semmle.label | url |
| main.rs:19:15:19:58 | res | semmle.label | res |
| main.rs:19:23:19:57 | ...::format(...) | semmle.label | ...::format(...) |
| main.rs:19:23:19:57 | ...::must_use(...) | semmle.label | ...::must_use(...) |
| main.rs:19:23:19:57 | MacroExpr | semmle.label | MacroExpr |
| main.rs:19:23:19:57 | { ... } | semmle.label | { ... } |
| main.rs:19:50:19:57 | password | semmle.label | password |
| main.rs:21:12:21:15 | post | semmle.label | post |
| main.rs:21:17:21:19 | url | semmle.label | url |
| main.rs:26:9:26:11 | url | semmle.label | url |
| main.rs:26:15:26:58 | res | semmle.label | res |
| main.rs:26:23:26:57 | ...::format(...) | semmle.label | ...::format(...) |
| main.rs:26:23:26:57 | ...::must_use(...) | semmle.label | ...::must_use(...) |
| main.rs:26:23:26:57 | MacroExpr | semmle.label | MacroExpr |
| main.rs:26:23:26:57 | { ... } | semmle.label | { ... } |
| main.rs:26:50:26:57 | password | semmle.label | password |
| main.rs:28:12:28:18 | request | semmle.label | request |
| main.rs:28:33:28:35 | url | semmle.label | url |
| main.rs:33:9:33:11 | url | semmle.label | url |
| main.rs:33:15:33:58 | res | semmle.label | res |
| main.rs:33:23:33:57 | ...::format(...) | semmle.label | ...::format(...) |
| main.rs:33:23:33:57 | ...::must_use(...) | semmle.label | ...::must_use(...) |
| main.rs:33:23:33:57 | MacroExpr | semmle.label | MacroExpr |
| main.rs:33:23:33:57 | { ... } | semmle.label | { ... } |
| main.rs:33:50:33:57 | password | semmle.label | password |
| main.rs:35:12:35:18 | request | semmle.label | request |
| main.rs:35:33:35:35 | url | semmle.label | url |
subpaths

View File

@@ -0,0 +1,4 @@
query: queries/security/CWE-311/CleartextTransmission.ql
postprocess:
- utils/test/PrettyPrintModels.ql
- utils/test/InlineExpectationsTestQuery.ql

View File

@@ -0,0 +1,44 @@
use http::Method;
use url::Url;
fn get_with_password_in_url() {
let password = "Hunter12";
let url = format!("example.com?password={}", password); // $ Source
reqwest::blocking::get(url).unwrap().text().unwrap(); // $ Alert[rust/cleartext-transmission]
}
fn get_with_password_in_constructed_url() {
let password = "Hunter12";
let address = format!("example.com?password={password}"); // $ Source
let url = Url::parse(&address).unwrap();
reqwest::blocking::get(url).unwrap().text().unwrap(); // $ Alert[rust/cleartext-transmission]
}
fn post_with_password_in_url() {
let password = "Hunter12";
let url = format!("example.com?password={}", password); // $ Source
let client = reqwest::Client::new();
client.post(url).body("body").send(); // $ Alert[rust/cleartext-transmission]
}
fn request_blocking_put_with_password_in_url() {
let password = "Hunter12";
let url = format!("example.com?password={}", password); // $ Source
let client = reqwest::blocking::Client::new();
client.request(Method::PUT, url).body("body").send(); // $ Alert[rust/cleartext-transmission]
}
fn request_put_with_password_in_url() {
let password = "Hunter12";
let url = format!("example.com?password={}", password); // $ Source
let client = reqwest::Client::new();
client.request(Method::PUT, url).body("body").send(); // $ Alert[rust/cleartext-transmission]
}
fn main() {
get_with_password_in_url();
get_with_password_in_constructed_url();
post_with_password_in_url();
request_blocking_put_with_password_in_url();
request_put_with_password_in_url();
}

View File

@@ -0,0 +1,5 @@
qltest_cargo_check: true
qltest_dependencies:
- reqwest = { version = "0.12.9", features = ["blocking"] }
- http = { version = "1.2.0" }
- url = { version = "2.5.4" }