Merge pull request #20829 from geoffw0/cert-checks

Rust: New Query rust/disabled-certificate-check
This commit is contained in:
Geoffrey White
2025-11-24 15:21:58 +00:00
committed by GitHub
21 changed files with 2092 additions and 2 deletions

View File

@@ -11,6 +11,7 @@ ql/rust/ql/src/queries/diagnostics/UnresolvedMacroCalls.ql
ql/rust/ql/src/queries/security/CWE-020/RegexInjection.ql
ql/rust/ql/src/queries/security/CWE-022/TaintedPath.ql
ql/rust/ql/src/queries/security/CWE-089/SqlInjection.ql
ql/rust/ql/src/queries/security/CWE-295/DisabledCertificateCheck.ql
ql/rust/ql/src/queries/security/CWE-311/CleartextTransmission.ql
ql/rust/ql/src/queries/security/CWE-312/CleartextLogging.ql
ql/rust/ql/src/queries/security/CWE-312/CleartextStorageDatabase.ql

View File

@@ -12,6 +12,7 @@ ql/rust/ql/src/queries/security/CWE-020/RegexInjection.ql
ql/rust/ql/src/queries/security/CWE-022/TaintedPath.ql
ql/rust/ql/src/queries/security/CWE-089/SqlInjection.ql
ql/rust/ql/src/queries/security/CWE-117/LogInjection.ql
ql/rust/ql/src/queries/security/CWE-295/DisabledCertificateCheck.ql
ql/rust/ql/src/queries/security/CWE-311/CleartextTransmission.ql
ql/rust/ql/src/queries/security/CWE-312/CleartextLogging.ql
ql/rust/ql/src/queries/security/CWE-312/CleartextStorageDatabase.ql

View File

@@ -12,6 +12,7 @@ ql/rust/ql/src/queries/security/CWE-020/RegexInjection.ql
ql/rust/ql/src/queries/security/CWE-022/TaintedPath.ql
ql/rust/ql/src/queries/security/CWE-089/SqlInjection.ql
ql/rust/ql/src/queries/security/CWE-117/LogInjection.ql
ql/rust/ql/src/queries/security/CWE-295/DisabledCertificateCheck.ql
ql/rust/ql/src/queries/security/CWE-311/CleartextTransmission.ql
ql/rust/ql/src/queries/security/CWE-312/CleartextLogging.ql
ql/rust/ql/src/queries/security/CWE-312/CleartextStorageDatabase.ql

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Added more detailed models for `std::fs` and `std::path`.

View File

@@ -0,0 +1,9 @@
extensions:
- addsTo:
pack: codeql/rust-all
extensible: sinkModel
data:
- ["<native_tls::TlsConnectorBuilder>::danger_accept_invalid_certs", "Argument[0]", "disable-certificate", "manual"]
- ["<native_tls::TlsConnectorBuilder>::danger_accept_invalid_hostnames", "Argument[0]", "disable-certificate", "manual"]
- ["<async_native_tls::connect::TlsConnector>::danger_accept_invalid_certs", "Argument[0]", "disable-certificate", "manual"]
- ["<async_native_tls::connect::TlsConnector>::danger_accept_invalid_hostnames", "Argument[0]", "disable-certificate", "manual"]

View File

@@ -11,6 +11,10 @@ extensions:
data:
- ["<reqwest::async_impl::client::Client>::request", "Argument[1]", "request-url", "manual"]
- ["<reqwest::blocking::client::Client>::request", "Argument[1]", "request-url", "manual"]
- ["<reqwest::async_impl::client::ClientBuilder>::danger_accept_invalid_certs", "Argument[0]", "disable-certificate", "manual"]
- ["<reqwest::async_impl::client::ClientBuilder>::danger_accept_invalid_hostnames", "Argument[0]", "disable-certificate", "manual"]
- ["<reqwest::blocking::client::ClientBuilder>::danger_accept_invalid_certs", "Argument[0]", "disable-certificate", "manual"]
- ["<reqwest::blocking::client::ClientBuilder>::danger_accept_invalid_hostnames", "Argument[0]", "disable-certificate", "manual"]
- addsTo:
pack: codeql/rust-all
extensible: summaryModel

View File

@@ -3,14 +3,27 @@ extensions:
pack: codeql/rust-all
extensible: sourceModel
data:
- ["std::fs::exists", "ReturnValue.Field[core::result::Result::Ok(0)]", "file", "manual"]
- ["std::fs::read", "ReturnValue.Field[core::result::Result::Ok(0)]", "file", "manual"]
- ["std::fs::read_dir", "ReturnValue.Field[core::result::Result::Ok(0)]", "file", "manual"]
- ["std::fs::read_to_string", "ReturnValue.Field[core::result::Result::Ok(0)]", "file", "manual"]
- ["std::fs::read_link", "ReturnValue.Field[core::result::Result::Ok(0)]", "file", "manual"]
- ["std::fs::metadata", "ReturnValue.Field[core::result::Result::Ok(0)]", "file", "manual"]
- ["std::fs::symlink_metadata", "ReturnValue.Field[core::result::Result::Ok(0)]", "file", "manual"]
- ["<std::fs::DirEntry>::path", "ReturnValue", "file", "manual"]
- ["<std::fs::DirEntry>::file_name", "ReturnValue", "file", "manual"]
- ["<std::fs::File>::open", "ReturnValue.Field[core::result::Result::Ok(0)]", "file", "manual"]
- ["<std::fs::File>::open_buffered", "ReturnValue.Field[core::result::Result::Ok(0)]", "file", "manual"]
- ["<std::fs::OpenOptions>::open", "ReturnValue.Field[core::result::Result::Ok(0)]", "file", "manual"]
- ["<std::path::Path>::exists", "ReturnValue", "file", "manual"]
- ["<std::path::Path>::try_exists", "ReturnValue.Field[core::result::Result::Ok(0)]", "file", "manual"]
- ["<std::path::Path>::is_file", "ReturnValue", "file", "manual"]
- ["<std::path::Path>::is_dir", "ReturnValue", "file", "manual"]
- ["<std::path::Path>::is_symlink", "ReturnValue", "file", "manual"]
- ["<std::path::Path>::metadata", "ReturnValue.Field[core::result::Result::Ok(0)]", "file", "manual"]
- ["<std::path::Path>::symlink_metadata", "ReturnValue.Field[core::result::Result::Ok(0)]", "file", "manual"]
- ["<std::path::Path>::read_dir", "ReturnValue.Field[core::result::Result::Ok(0)]", "file", "manual"]
- ["<std::path::Path>::read_link", "ReturnValue.Field[core::result::Result::Ok(0)]", "file", "manual"]
- addsTo:
pack: codeql/rust-all
extensible: sinkModel
@@ -68,3 +81,12 @@ extensions:
- ["<std::path::Path>::with_extension", "Argument[Self].Reference", "ReturnValue", "taint", "manual"]
- ["<std::path::Path>::with_file_name", "Argument[Self].Reference", "ReturnValue", "taint", "manual"]
- ["<std::path::Path>::with_file_name", "Argument[0]", "ReturnValue", "taint", "manual"]
- ["<std::fs::Metadata>::accessed", "Argument[self].Reference", "ReturnValue.Field[core::result::Result::Ok(0)]", "taint", "manual"]
- ["<std::fs::Metadata>::created", "Argument[self].Reference", "ReturnValue.Field[core::result::Result::Ok(0)]", "taint", "manual"]
- ["<std::fs::Metadata>::file_type", "Argument[self].Reference", "ReturnValue", "taint", "manual"]
- ["<std::fs::Metadata>::is_file", "Argument[self].Reference", "ReturnValue", "taint", "manual"]
- ["<std::fs::Metadata>::is_dir", "Argument[self].Reference", "ReturnValue", "taint", "manual"]
- ["<std::fs::Metadata>::is_symlink", "Argument[self].Reference", "ReturnValue", "taint", "manual"]
- ["<std::fs::Metadata>::len", "Argument[self].Reference", "ReturnValue", "taint", "manual"]
- ["<std::fs::Metadata>::modified", "Argument[self].Reference", "ReturnValue.Field[core::result::Result::Ok(0)]", "taint", "manual"]
- ["<std::fs::Metadata>::permissions", "Argument[self].Reference", "ReturnValue", "taint", "manual"]

View File

@@ -0,0 +1,45 @@
/**
* Provides classes and predicates for reasoning about disabled certificate
* check vulnerabilities.
*/
import rust
private import codeql.rust.dataflow.DataFlow
private import codeql.rust.dataflow.FlowSink
private import codeql.rust.Concepts
private import codeql.rust.dataflow.internal.Node as Node
/**
* Provides default sinks for detecting disabled certificate check
* vulnerabilities, as well as extension points for adding your own.
*/
module DisabledCertificateCheckExtensions {
/**
* A data flow sink for disabled certificate check vulnerabilities.
*/
abstract class Sink extends QuerySink::Range {
override string getSinkType() { result = "DisabledCertificateCheck" }
}
/**
* A sink for disabled certificate check vulnerabilities from model data.
*/
private class ModelsAsDataSink extends Sink {
ModelsAsDataSink() { sinkNode(this, "disable-certificate") }
}
/**
* A heuristic sink for disabled certificate check vulnerabilities based on function names.
*/
private class HeuristicSink extends Sink {
HeuristicSink() {
exists(CallExprBase fc |
fc.getStaticTarget().(Function).getName().getText() =
["danger_accept_invalid_certs", "danger_accept_invalid_hostnames"] and
fc.getArg(0) = this.asExpr() and
// don't duplicate modeled sinks
not exists(ModelsAsDataSink s | s.(Node::FlowSummaryNode).getSinkElement().getCall() = fc)
)
}
}
}

View File

@@ -0,0 +1,4 @@
---
category: newQuery
---
* Added a new query `rust/disabled-certificate-check`, to detect disabled TLS certificate checks.

View File

@@ -0,0 +1,42 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>
The <code>danger_accept_invalid_certs</code> option on TLS connectors and HTTP clients controls whether certificate verification is performed. If this option is set to <code>true</code>, the client will accept any certificate, making it susceptible to man-in-the-middle attacks.
</p>
<p>
Similarly, the <code>danger_accept_invalid_hostnames</code> option controls whether hostname verification is performed. If this option is set to <code>true</code>, the client will accept any valid certificate regardless of the site that certificate is for, again making it susceptible to man-in-the-middle attacks.
</p>
</overview>
<recommendation>
<p>
Do not set <code>danger_accept_invalid_certs</code> or <code>danger_accept_invalid_hostnames</code> to <code>true</code>, except in controlled environments such as tests. In production, always ensure certificate and hostname verification is enabled to prevent security risks.
</p>
</recommendation>
<example>
<p>
The following code snippet shows a function that creates an HTTP client with certificate verification disabled:
</p>
<sample src="DisabledCertificateCheckBad.rs"/>
<p>
In production code, always configure clients to verify certificates:
</p>
<sample src="DisabledCertificateCheckGood.rs"/>
</example>
<references>
<li>
Rust native-tls crate: <a href="https://docs.rs/native-tls/latest/native_tls/struct.TlsConnectorBuilder.html">TlsConnectorBuilder</a>.
</li>
<li>
Rust reqwest crate: <a href="https://docs.rs/reqwest/latest/reqwest/struct.ClientBuilder.html">ClientBuilder</a>.
</li>
<li>
SSL.com: <a href="https://www.ssl.com/article/browsers-and-certificate-validation/">Browsers and Certificate Validation</a>.
</li>
</references>
</qhelp>

View File

@@ -0,0 +1,47 @@
/**
* @name Disabled TLS certificate check
* @description An application that disables TLS certificate checking is more vulnerable to
* man-in-the-middle attacks.
* @kind path-problem
* @problem.severity warning
* @security-severity 7.5
* @precision high
* @id rust/disabled-certificate-check
* @tags security
* external/cwe/cwe-295
*/
import rust
import codeql.rust.dataflow.DataFlow
import codeql.rust.dataflow.TaintTracking
import codeql.rust.security.DisabledCertificateCheckExtensions
import codeql.rust.Concepts
/**
* A taint configuration for disabled TLS certificate checks.
*/
module DisabledCertificateCheckConfig implements DataFlow::ConfigSig {
import DisabledCertificateCheckExtensions
predicate isSource(DataFlow::Node node) {
// the constant `true`
node.asExpr().(BooleanLiteralExpr).getTextValue() = "true"
or
// a value controlled by a potential attacker
node instanceof ActiveThreatModelSource
}
predicate isSink(DataFlow::Node node) { node instanceof Sink }
predicate observeDiffInformedIncrementalMode() { any() }
}
module DisabledCertificateCheckFlow = TaintTracking::Global<DisabledCertificateCheckConfig>;
import DisabledCertificateCheckFlow::PathGraph
from
DisabledCertificateCheckFlow::PathNode sourceNode, DisabledCertificateCheckFlow::PathNode sinkNode
where DisabledCertificateCheckFlow::flowPath(sourceNode, sinkNode)
select sinkNode.getNode(), sourceNode, sinkNode,
"Disabling TLS certificate validation can expose the application to man-in-the-middle attacks."

View File

@@ -0,0 +1,6 @@
// BAD: Disabling certificate validation in Rust
let _client = reqwest::Client::builder()
.danger_accept_invalid_certs(true) // disables certificate validation
.build()
.unwrap();

View File

@@ -0,0 +1,10 @@
// GOOD: Certificate validation is enabled (default)
let _client = reqwest::Client::builder()
.danger_accept_invalid_certs(false) // certificate validation enabled explicitly
.build()
.unwrap();
let _client = native_tls::TlsConnector::builder() // certificate validation enabled by default
.build()
.unwrap();

View File

@@ -22,6 +22,7 @@ private import codeql.rust.security.AccessInvalidPointerExtensions
private import codeql.rust.security.CleartextLoggingExtensions
private import codeql.rust.security.CleartextStorageDatabaseExtensions
private import codeql.rust.security.CleartextTransmissionExtensions
private import codeql.rust.security.DisabledCertificateCheckExtensions
private import codeql.rust.security.HardcodedCryptographicValueExtensions
private import codeql.rust.security.InsecureCookieExtensions
private import codeql.rust.security.LogInjectionExtensions

View File

@@ -4,8 +4,10 @@
| test.rs:17:31:17:38 | ...::read | Flow source 'FileSource' of type file (DEFAULT). |
| test.rs:22:22:22:39 | ...::read_to_string | Flow source 'FileSource' of type file (DEFAULT). |
| test.rs:22:22:22:39 | ...::read_to_string | Flow source 'FileSource' of type file (DEFAULT). |
| test.rs:26:18:26:29 | ...::read_dir | Flow source 'FileSource' of type file (DEFAULT). |
| test.rs:29:22:29:25 | path | Flow source 'FileSource' of type file (DEFAULT). |
| test.rs:43:27:43:35 | file_name | Flow source 'FileSource' of type file (DEFAULT). |
| test.rs:51:52:51:59 | read_dir | Flow source 'FileSource' of type file (DEFAULT). |
| test.rs:54:22:54:25 | path | Flow source 'FileSource' of type file (DEFAULT). |
| test.rs:55:27:55:35 | file_name | Flow source 'FileSource' of type file (DEFAULT). |
| test.rs:65:22:65:34 | ...::read_link | Flow source 'FileSource' of type file (DEFAULT). |

View File

@@ -23,7 +23,7 @@ fn test_fs() -> Result<(), Box<dyn std::error::Error>> {
sink(buffer); // $ hasTaintFlow="file.txt"
}
for entry in fs::read_dir("directory")? {
for entry in fs::read_dir("directory")? { // $ Alert[rust/summary/taint-sources]
let e = entry?;
let path = e.path(); // $ Alert[rust/summary/taint-sources]
@@ -48,7 +48,7 @@ fn test_fs() -> Result<(), Box<dyn std::error::Error>> {
sink(file_name.clone().as_encoded_bytes()); // $ MISSING: hasTaintFlow
sink(file_name); // $ hasTaintFlow
}
for entry in std::path::Path::new("directory").read_dir()? {
for entry in std::path::Path::new("directory").read_dir()? { // $ Alert[rust/summary/taint-sources]
let e = entry?;
let path = e.path(); // $ Alert[rust/summary/taint-sources]

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,129 @@
#select
| main.rs:4:4:4:30 | danger_accept_invalid_certs | main.rs:4:32:4:35 | true | main.rs:4:4:4:30 | danger_accept_invalid_certs | Disabling TLS certificate validation can expose the application to man-in-the-middle attacks. |
| main.rs:9:4:9:34 | danger_accept_invalid_hostnames | main.rs:9:36:9:39 | true | main.rs:9:4:9:34 | danger_accept_invalid_hostnames | Disabling TLS certificate validation can expose the application to man-in-the-middle attacks. |
| main.rs:16:4:16:30 | danger_accept_invalid_certs | main.rs:16:32:16:35 | true | main.rs:16:4:16:30 | danger_accept_invalid_certs | Disabling TLS certificate validation can expose the application to man-in-the-middle attacks. |
| main.rs:17:4:17:34 | danger_accept_invalid_hostnames | main.rs:17:36:17:39 | true | main.rs:17:4:17:34 | danger_accept_invalid_hostnames | Disabling TLS certificate validation can expose the application to man-in-the-middle attacks. |
| main.rs:37:4:37:30 | danger_accept_invalid_certs | main.rs:37:32:37:35 | true | main.rs:37:4:37:30 | danger_accept_invalid_certs | Disabling TLS certificate validation can expose the application to man-in-the-middle attacks. |
| main.rs:42:4:42:34 | danger_accept_invalid_hostnames | main.rs:42:36:42:39 | true | main.rs:42:4:42:34 | danger_accept_invalid_hostnames | Disabling TLS certificate validation can expose the application to man-in-the-middle attacks. |
| main.rs:47:4:47:30 | danger_accept_invalid_certs | main.rs:47:32:47:35 | true | main.rs:47:4:47:30 | danger_accept_invalid_certs | Disabling TLS certificate validation can expose the application to man-in-the-middle attacks. |
| main.rs:48:4:48:34 | danger_accept_invalid_hostnames | main.rs:48:36:48:39 | true | main.rs:48:4:48:34 | danger_accept_invalid_hostnames | Disabling TLS certificate validation can expose the application to man-in-the-middle attacks. |
| main.rs:55:4:55:30 | danger_accept_invalid_certs | main.rs:55:32:55:35 | true | main.rs:55:4:55:30 | danger_accept_invalid_certs | Disabling TLS certificate validation can expose the application to man-in-the-middle attacks. |
| main.rs:56:4:56:34 | danger_accept_invalid_hostnames | main.rs:56:36:56:39 | true | main.rs:56:4:56:34 | danger_accept_invalid_hostnames | Disabling TLS certificate validation can expose the application to man-in-the-middle attacks. |
| main.rs:83:4:83:30 | danger_accept_invalid_certs | main.rs:74:15:74:18 | true | main.rs:83:4:83:30 | danger_accept_invalid_certs | Disabling TLS certificate validation can expose the application to man-in-the-middle attacks. |
| main.rs:88:4:88:30 | danger_accept_invalid_certs | main.rs:75:22:75:25 | true | main.rs:88:4:88:30 | danger_accept_invalid_certs | Disabling TLS certificate validation can expose the application to man-in-the-middle attacks. |
| main.rs:93:4:93:30 | danger_accept_invalid_certs | main.rs:154:17:154:20 | true | main.rs:93:4:93:30 | danger_accept_invalid_certs | Disabling TLS certificate validation can expose the application to man-in-the-middle attacks. |
| main.rs:109:4:109:34 | danger_accept_invalid_hostnames | main.rs:107:17:107:31 | ...::exists | main.rs:109:4:109:34 | danger_accept_invalid_hostnames | Disabling TLS certificate validation can expose the application to man-in-the-middle attacks. |
| main.rs:115:4:115:34 | danger_accept_invalid_hostnames | main.rs:113:43:113:50 | metadata | main.rs:115:4:115:34 | danger_accept_invalid_hostnames | Disabling TLS certificate validation can expose the application to man-in-the-middle attacks. |
| main.rs:121:4:121:34 | danger_accept_invalid_hostnames | main.rs:119:11:119:27 | ...::metadata | main.rs:121:4:121:34 | danger_accept_invalid_hostnames | Disabling TLS certificate validation can expose the application to man-in-the-middle attacks. |
| main.rs:146:4:146:34 | danger_accept_invalid_hostnames | main.rs:144:39:144:42 | true | main.rs:146:4:146:34 | danger_accept_invalid_hostnames | Disabling TLS certificate validation can expose the application to man-in-the-middle attacks. |
edges
| main.rs:4:32:4:35 | true | main.rs:4:4:4:30 | danger_accept_invalid_certs | provenance | MaD:1 Sink:MaD:1 |
| main.rs:9:36:9:39 | true | main.rs:9:4:9:34 | danger_accept_invalid_hostnames | provenance | MaD:2 Sink:MaD:2 |
| main.rs:16:32:16:35 | true | main.rs:16:4:16:30 | danger_accept_invalid_certs | provenance | MaD:1 Sink:MaD:1 |
| main.rs:17:36:17:39 | true | main.rs:17:4:17:34 | danger_accept_invalid_hostnames | provenance | MaD:2 Sink:MaD:2 |
| main.rs:37:32:37:35 | true | main.rs:37:4:37:30 | danger_accept_invalid_certs | provenance | MaD:3 Sink:MaD:3 |
| main.rs:42:36:42:39 | true | main.rs:42:4:42:34 | danger_accept_invalid_hostnames | provenance | MaD:6 Sink:MaD:6 |
| main.rs:47:32:47:35 | true | main.rs:47:4:47:30 | danger_accept_invalid_certs | provenance | MaD:3 Sink:MaD:3 |
| main.rs:48:36:48:39 | true | main.rs:48:4:48:34 | danger_accept_invalid_hostnames | provenance | MaD:4 Sink:MaD:4 |
| main.rs:55:32:55:35 | true | main.rs:55:4:55:30 | danger_accept_invalid_certs | provenance | MaD:5 Sink:MaD:5 |
| main.rs:56:36:56:39 | true | main.rs:56:4:56:34 | danger_accept_invalid_hostnames | provenance | MaD:6 Sink:MaD:6 |
| main.rs:73:19:73:40 | ...: bool | main.rs:93:32:93:47 | sometimes_global | provenance | |
| main.rs:74:6:74:11 | always | main.rs:83:32:83:37 | always | provenance | |
| main.rs:74:15:74:18 | true | main.rs:74:6:74:11 | always | provenance | |
| main.rs:75:6:75:18 | mut sometimes | main.rs:88:32:88:40 | sometimes | provenance | |
| main.rs:75:22:75:25 | true | main.rs:75:6:75:18 | mut sometimes | provenance | |
| main.rs:83:32:83:37 | always | main.rs:83:4:83:30 | danger_accept_invalid_certs | provenance | MaD:1 Sink:MaD:1 |
| main.rs:88:32:88:40 | sometimes | main.rs:88:4:88:30 | danger_accept_invalid_certs | provenance | MaD:1 Sink:MaD:1 |
| main.rs:93:32:93:47 | sometimes_global | main.rs:93:4:93:30 | danger_accept_invalid_certs | provenance | MaD:1 Sink:MaD:1 |
| main.rs:107:6:107:7 | b1 | main.rs:109:36:109:37 | b1 | provenance | |
| main.rs:107:17:107:31 | ...::exists | main.rs:107:17:107:42 | ...::exists(...) [Ok] | provenance | Src:MaD:8 |
| main.rs:107:17:107:42 | ...::exists(...) [Ok] | main.rs:107:17:107:51 | ... .unwrap() | provenance | MaD:10 |
| main.rs:107:17:107:51 | ... .unwrap() | main.rs:107:6:107:7 | b1 | provenance | |
| main.rs:109:36:109:37 | b1 | main.rs:109:4:109:34 | danger_accept_invalid_hostnames | provenance | MaD:2 Sink:MaD:2 |
| main.rs:113:6:113:7 | b2 | main.rs:115:36:115:37 | b2 | provenance | |
| main.rs:113:11:113:52 | ... .metadata() [Ok] | main.rs:113:11:113:61 | ... .unwrap() | provenance | MaD:10 |
| main.rs:113:11:113:61 | ... .unwrap() | main.rs:113:11:113:71 | ... .is_file() | provenance | MaD:12 |
| main.rs:113:11:113:71 | ... .is_file() | main.rs:113:6:113:7 | b2 | provenance | |
| main.rs:113:43:113:50 | metadata | main.rs:113:11:113:52 | ... .metadata() [Ok] | provenance | Src:MaD:7 |
| main.rs:115:36:115:37 | b2 | main.rs:115:4:115:34 | danger_accept_invalid_hostnames | provenance | MaD:2 Sink:MaD:2 |
| main.rs:119:6:119:7 | b3 | main.rs:121:36:121:37 | b3 | provenance | |
| main.rs:119:11:119:27 | ...::metadata | main.rs:119:11:119:38 | ...::metadata(...) [Ok] | provenance | Src:MaD:9 |
| main.rs:119:11:119:38 | ...::metadata(...) [Ok] | main.rs:119:11:119:47 | ... .unwrap() | provenance | MaD:10 |
| main.rs:119:11:119:47 | ... .unwrap() | main.rs:119:11:119:56 | ... .is_dir() | provenance | MaD:11 |
| main.rs:119:11:119:56 | ... .is_dir() | main.rs:119:6:119:7 | b3 | provenance | |
| main.rs:121:36:121:37 | b3 | main.rs:121:4:121:34 | danger_accept_invalid_hostnames | provenance | MaD:2 Sink:MaD:2 |
| main.rs:144:6:144:7 | b6 | main.rs:146:36:146:37 | b6 | provenance | |
| main.rs:144:39:144:42 | true | main.rs:144:6:144:7 | b6 | provenance | |
| main.rs:146:36:146:37 | b6 | main.rs:146:4:146:34 | danger_accept_invalid_hostnames | provenance | MaD:2 Sink:MaD:2 |
| main.rs:154:17:154:20 | true | main.rs:73:19:73:40 | ...: bool | provenance | |
models
| 1 | Sink: <native_tls::TlsConnectorBuilder>::danger_accept_invalid_certs; Argument[0]; disable-certificate |
| 2 | Sink: <native_tls::TlsConnectorBuilder>::danger_accept_invalid_hostnames; Argument[0]; disable-certificate |
| 3 | Sink: <reqwest::async_impl::client::ClientBuilder>::danger_accept_invalid_certs; Argument[0]; disable-certificate |
| 4 | Sink: <reqwest::async_impl::client::ClientBuilder>::danger_accept_invalid_hostnames; Argument[0]; disable-certificate |
| 5 | Sink: <reqwest::blocking::client::ClientBuilder>::danger_accept_invalid_certs; Argument[0]; disable-certificate |
| 6 | Sink: <reqwest::blocking::client::ClientBuilder>::danger_accept_invalid_hostnames; Argument[0]; disable-certificate |
| 7 | Source: <std::path::Path>::metadata; ReturnValue.Field[core::result::Result::Ok(0)]; file |
| 8 | Source: std::fs::exists; ReturnValue.Field[core::result::Result::Ok(0)]; file |
| 9 | Source: std::fs::metadata; ReturnValue.Field[core::result::Result::Ok(0)]; file |
| 10 | Summary: <core::result::Result>::unwrap; Argument[self].Field[core::result::Result::Ok(0)]; ReturnValue; value |
| 11 | Summary: <std::fs::Metadata>::is_dir; Argument[self].Reference; ReturnValue; taint |
| 12 | Summary: <std::fs::Metadata>::is_file; Argument[self].Reference; ReturnValue; taint |
nodes
| main.rs:4:4:4:30 | danger_accept_invalid_certs | semmle.label | danger_accept_invalid_certs |
| main.rs:4:32:4:35 | true | semmle.label | true |
| main.rs:9:4:9:34 | danger_accept_invalid_hostnames | semmle.label | danger_accept_invalid_hostnames |
| main.rs:9:36:9:39 | true | semmle.label | true |
| main.rs:16:4:16:30 | danger_accept_invalid_certs | semmle.label | danger_accept_invalid_certs |
| main.rs:16:32:16:35 | true | semmle.label | true |
| main.rs:17:4:17:34 | danger_accept_invalid_hostnames | semmle.label | danger_accept_invalid_hostnames |
| main.rs:17:36:17:39 | true | semmle.label | true |
| main.rs:37:4:37:30 | danger_accept_invalid_certs | semmle.label | danger_accept_invalid_certs |
| main.rs:37:32:37:35 | true | semmle.label | true |
| main.rs:42:4:42:34 | danger_accept_invalid_hostnames | semmle.label | danger_accept_invalid_hostnames |
| main.rs:42:36:42:39 | true | semmle.label | true |
| main.rs:47:4:47:30 | danger_accept_invalid_certs | semmle.label | danger_accept_invalid_certs |
| main.rs:47:32:47:35 | true | semmle.label | true |
| main.rs:48:4:48:34 | danger_accept_invalid_hostnames | semmle.label | danger_accept_invalid_hostnames |
| main.rs:48:36:48:39 | true | semmle.label | true |
| main.rs:55:4:55:30 | danger_accept_invalid_certs | semmle.label | danger_accept_invalid_certs |
| main.rs:55:32:55:35 | true | semmle.label | true |
| main.rs:56:4:56:34 | danger_accept_invalid_hostnames | semmle.label | danger_accept_invalid_hostnames |
| main.rs:56:36:56:39 | true | semmle.label | true |
| main.rs:73:19:73:40 | ...: bool | semmle.label | ...: bool |
| main.rs:74:6:74:11 | always | semmle.label | always |
| main.rs:74:15:74:18 | true | semmle.label | true |
| main.rs:75:6:75:18 | mut sometimes | semmle.label | mut sometimes |
| main.rs:75:22:75:25 | true | semmle.label | true |
| main.rs:83:4:83:30 | danger_accept_invalid_certs | semmle.label | danger_accept_invalid_certs |
| main.rs:83:32:83:37 | always | semmle.label | always |
| main.rs:88:4:88:30 | danger_accept_invalid_certs | semmle.label | danger_accept_invalid_certs |
| main.rs:88:32:88:40 | sometimes | semmle.label | sometimes |
| main.rs:93:4:93:30 | danger_accept_invalid_certs | semmle.label | danger_accept_invalid_certs |
| main.rs:93:32:93:47 | sometimes_global | semmle.label | sometimes_global |
| main.rs:107:6:107:7 | b1 | semmle.label | b1 |
| main.rs:107:17:107:31 | ...::exists | semmle.label | ...::exists |
| main.rs:107:17:107:42 | ...::exists(...) [Ok] | semmle.label | ...::exists(...) [Ok] |
| main.rs:107:17:107:51 | ... .unwrap() | semmle.label | ... .unwrap() |
| main.rs:109:4:109:34 | danger_accept_invalid_hostnames | semmle.label | danger_accept_invalid_hostnames |
| main.rs:109:36:109:37 | b1 | semmle.label | b1 |
| main.rs:113:6:113:7 | b2 | semmle.label | b2 |
| main.rs:113:11:113:52 | ... .metadata() [Ok] | semmle.label | ... .metadata() [Ok] |
| main.rs:113:11:113:61 | ... .unwrap() | semmle.label | ... .unwrap() |
| main.rs:113:11:113:71 | ... .is_file() | semmle.label | ... .is_file() |
| main.rs:113:43:113:50 | metadata | semmle.label | metadata |
| main.rs:115:4:115:34 | danger_accept_invalid_hostnames | semmle.label | danger_accept_invalid_hostnames |
| main.rs:115:36:115:37 | b2 | semmle.label | b2 |
| main.rs:119:6:119:7 | b3 | semmle.label | b3 |
| main.rs:119:11:119:27 | ...::metadata | semmle.label | ...::metadata |
| main.rs:119:11:119:38 | ...::metadata(...) [Ok] | semmle.label | ...::metadata(...) [Ok] |
| main.rs:119:11:119:47 | ... .unwrap() | semmle.label | ... .unwrap() |
| main.rs:119:11:119:56 | ... .is_dir() | semmle.label | ... .is_dir() |
| main.rs:121:4:121:34 | danger_accept_invalid_hostnames | semmle.label | danger_accept_invalid_hostnames |
| main.rs:121:36:121:37 | b3 | semmle.label | b3 |
| main.rs:144:6:144:7 | b6 | semmle.label | b6 |
| main.rs:144:39:144:42 | true | semmle.label | true |
| main.rs:146:4:146:34 | danger_accept_invalid_hostnames | semmle.label | danger_accept_invalid_hostnames |
| main.rs:146:36:146:37 | b6 | semmle.label | b6 |
| main.rs:154:17:154:20 | true | semmle.label | true |
subpaths

View File

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

View File

@@ -0,0 +1,157 @@
fn test_native_tls() {
// unsafe
let _client = native_tls::TlsConnector::builder()
.danger_accept_invalid_certs(true) // $ Alert[rust/disabled-certificate-check]
.build()
.unwrap();
let _client = native_tls::TlsConnector::builder()
.danger_accept_invalid_hostnames(true) // $ Alert[rust/disabled-certificate-check]
.build()
.unwrap();
let _client = native_tls::TlsConnector::builder()
.min_protocol_version(Some(native_tls::Protocol::Tlsv12))
.use_sni(true)
.danger_accept_invalid_certs(true) // $ Alert[rust/disabled-certificate-check]
.danger_accept_invalid_hostnames(true) // $ Alert[rust/disabled-certificate-check]
.build()
.unwrap();
// safe
let _client = native_tls::TlsConnector::builder()
.danger_accept_invalid_certs(false) // good
.danger_accept_invalid_hostnames(false) // good
.build()
.unwrap();
// default (safe)
let _client = native_tls::TlsConnector::builder()
.build()
.unwrap();
}
fn test_reqwest() {
// unsafe
let _client = reqwest::Client::builder()
.danger_accept_invalid_certs(true) // $ Alert[rust/disabled-certificate-check]
.build()
.unwrap();
let _client = reqwest::blocking::ClientBuilder::new()
.danger_accept_invalid_hostnames(true) // $ Alert[rust/disabled-certificate-check]
.build()
.unwrap();
let _client = reqwest::ClientBuilder::new()
.danger_accept_invalid_certs(true) // $ Alert[rust/disabled-certificate-check]
.danger_accept_invalid_hostnames(true) // $ Alert[rust/disabled-certificate-check]
.build()
.unwrap();
let _client = reqwest::blocking::Client::builder()
.tcp_keepalive(std::time::Duration::from_secs(30))
.https_only(true)
.danger_accept_invalid_certs(true) // $ Alert[rust/disabled-certificate-check]
.danger_accept_invalid_hostnames(true) // $ Alert[rust/disabled-certificate-check]
.build()
.unwrap();
// safe
let _client = reqwest::blocking::Client::builder()
.danger_accept_invalid_certs(false) // good
.danger_accept_invalid_hostnames(false) // good
.build()
.unwrap();
// default (safe)
let _client = reqwest::blocking::Client::builder()
.build()
.unwrap();
}
fn test_data_flow(sometimes_global: bool) {
let always = true; // $ Source=always
let mut sometimes = true; // $ Source=sometimes
let never = false;
if rand::random_range(0 .. 2) == 0 {
sometimes = false;
}
let _client = native_tls::TlsConnector::builder()
.danger_accept_invalid_certs(always) // $ Alert[rust/disabled-certificate-check]=always
.build()
.unwrap();
let _client = native_tls::TlsConnector::builder()
.danger_accept_invalid_certs(sometimes) // $ Alert[rust/disabled-certificate-check]=sometimes
.build()
.unwrap();
let _client = native_tls::TlsConnector::builder()
.danger_accept_invalid_certs(sometimes_global) // $ Alert[rust/disabled-certificate-check]=arg
.build()
.unwrap();
let _client = native_tls::TlsConnector::builder()
.danger_accept_invalid_certs(never) // good
.build()
.unwrap();
}
fn test_threat_model_source() {
// hostname setting from `fs` functions returning `bool` directly
// (these are highly unnatural but serve to create simple tests)
let b1: bool = std::fs::exists("main.rs").unwrap(); // $ Source=exists
let _client = native_tls::TlsConnector::builder()
.danger_accept_invalid_hostnames(b1) // $ Alert[rust/disabled-certificate-check]=exists
.build()
.unwrap();
let b2 = std::path::Path::new("main.rs").metadata().unwrap().is_file(); // $ Source=is_file
let _client = native_tls::TlsConnector::builder()
.danger_accept_invalid_hostnames(b2) // $ Alert[rust/disabled-certificate-check]=is_file
.build()
.unwrap();
let b3 = std::fs::metadata("main.rs").unwrap().is_dir(); // $ Source=is_dir
let _client = native_tls::TlsConnector::builder()
.danger_accept_invalid_hostnames(b3) // $ Alert[rust/disabled-certificate-check]=is_dir
.build()
.unwrap();
// hostname setting from `stdin`, parsed to `bool`
// (these are a little closer to something real)
let mut input_line = String::new();
let input = std::io::stdin();
input.read_line(&mut input_line).unwrap();
let b4: bool = input_line.parse::<bool>().unwrap_or(false);
let _client = native_tls::TlsConnector::builder()
.danger_accept_invalid_hostnames(b4) // $ MISSING: Alert[rust/disabled-certificate-check]=stdin
.build()
.unwrap();
let b5 = std::str::FromStr::from_str(&input_line).unwrap_or(false);
let _client = native_tls::TlsConnector::builder()
.danger_accept_invalid_hostnames(b5) // $ MISSING: Alert[rust/disabled-certificate-check]=stdin
.build()
.unwrap();
let b6 = if (input_line == "true") { true } else { false }; // $ Source=true
let _client = native_tls::TlsConnector::builder()
.danger_accept_invalid_hostnames(b6) // $ Alert[rust/disabled-certificate-check]=true
.build()
.unwrap();
}
fn main() {
test_native_tls();
test_reqwest();
test_data_flow(true); // $ Source=arg
test_data_flow(false);
test_threat_model_source();
}

View File

@@ -0,0 +1,5 @@
qltest_cargo_check: true
qltest_dependencies:
- reqwest = { version = "0.12.9", features = ["blocking"] }
- native-tls = { version = "0.2.14" }
- rand = { version = "0.9.2" }