From 459f00ab415e1263c0756a03516e51e9963adc52 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 15 Sep 2025 11:25:11 +0000 Subject: [PATCH 01/12] Initial plan From e630bf86bdd0f9a678b234f04f11f4ba883b5571 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 15 Sep 2025 11:44:05 +0000 Subject: [PATCH 02/12] Implement Rust non-HTTPS URL query (CWE-319) Co-authored-by: geoffw0 <40627776+geoffw0@users.noreply.github.com> --- .../rust-code-scanning.qls.expected | 1 + .../rust-security-and-quality.qls.expected | 1 + .../rust-security-extended.qls.expected | 1 + .../rust/security/UseOfHttpExtensions.qll | 60 + .../change-notes/2025-09-15-non-https-url.md | 4 + .../queries/security/CWE-319/UseOfHttp.qhelp | 48 + .../src/queries/security/CWE-319/UseOfHttp.ql | 42 + .../queries/security/CWE-319/UseOfHttpBad.rs | 10 + .../queries/security/CWE-319/UseOfHttpGood.rs | 10 + rust/ql/src/queries/summary/Stats.qll | 1 + .../query-tests/security/CWE-319/Cargo.lock | 1574 +++++++++++++++++ .../security/CWE-319/UseOfHttp.expected | 78 + .../security/CWE-319/UseOfHttp.qlref | 4 + .../test/query-tests/security/CWE-319/main.rs | 65 + .../query-tests/security/CWE-319/options.yml | 3 + 15 files changed, 1902 insertions(+) create mode 100644 rust/ql/lib/codeql/rust/security/UseOfHttpExtensions.qll create mode 100644 rust/ql/src/change-notes/2025-09-15-non-https-url.md create mode 100644 rust/ql/src/queries/security/CWE-319/UseOfHttp.qhelp create mode 100644 rust/ql/src/queries/security/CWE-319/UseOfHttp.ql create mode 100644 rust/ql/src/queries/security/CWE-319/UseOfHttpBad.rs create mode 100644 rust/ql/src/queries/security/CWE-319/UseOfHttpGood.rs create mode 100644 rust/ql/test/query-tests/security/CWE-319/Cargo.lock create mode 100644 rust/ql/test/query-tests/security/CWE-319/UseOfHttp.expected create mode 100644 rust/ql/test/query-tests/security/CWE-319/UseOfHttp.qlref create mode 100644 rust/ql/test/query-tests/security/CWE-319/main.rs create mode 100644 rust/ql/test/query-tests/security/CWE-319/options.yml diff --git a/rust/ql/integration-tests/query-suite/rust-code-scanning.qls.expected b/rust/ql/integration-tests/query-suite/rust-code-scanning.qls.expected index b601905e6a30..1b8e1015a1ff 100644 --- a/rust/ql/integration-tests/query-suite/rust-code-scanning.qls.expected +++ b/rust/ql/integration-tests/query-suite/rust-code-scanning.qls.expected @@ -14,6 +14,7 @@ ql/rust/ql/src/queries/security/CWE-089/SqlInjection.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 +ql/rust/ql/src/queries/security/CWE-319/UseOfHttp.ql ql/rust/ql/src/queries/security/CWE-327/BrokenCryptoAlgorithm.ql ql/rust/ql/src/queries/security/CWE-328/WeakSensitiveDataHashing.ql ql/rust/ql/src/queries/security/CWE-770/UncontrolledAllocationSize.ql diff --git a/rust/ql/integration-tests/query-suite/rust-security-and-quality.qls.expected b/rust/ql/integration-tests/query-suite/rust-security-and-quality.qls.expected index 074cb2ec8888..a2d2e2b820c5 100644 --- a/rust/ql/integration-tests/query-suite/rust-security-and-quality.qls.expected +++ b/rust/ql/integration-tests/query-suite/rust-security-and-quality.qls.expected @@ -15,6 +15,7 @@ ql/rust/ql/src/queries/security/CWE-117/LogInjection.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 +ql/rust/ql/src/queries/security/CWE-319/UseOfHttp.ql ql/rust/ql/src/queries/security/CWE-327/BrokenCryptoAlgorithm.ql ql/rust/ql/src/queries/security/CWE-328/WeakSensitiveDataHashing.ql ql/rust/ql/src/queries/security/CWE-696/BadCtorInitialization.ql diff --git a/rust/ql/integration-tests/query-suite/rust-security-extended.qls.expected b/rust/ql/integration-tests/query-suite/rust-security-extended.qls.expected index 38846e281eb8..9000990ad841 100644 --- a/rust/ql/integration-tests/query-suite/rust-security-extended.qls.expected +++ b/rust/ql/integration-tests/query-suite/rust-security-extended.qls.expected @@ -15,6 +15,7 @@ ql/rust/ql/src/queries/security/CWE-117/LogInjection.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 +ql/rust/ql/src/queries/security/CWE-319/UseOfHttp.ql ql/rust/ql/src/queries/security/CWE-327/BrokenCryptoAlgorithm.ql ql/rust/ql/src/queries/security/CWE-328/WeakSensitiveDataHashing.ql ql/rust/ql/src/queries/security/CWE-770/UncontrolledAllocationSize.ql diff --git a/rust/ql/lib/codeql/rust/security/UseOfHttpExtensions.qll b/rust/ql/lib/codeql/rust/security/UseOfHttpExtensions.qll new file mode 100644 index 000000000000..026880785b6c --- /dev/null +++ b/rust/ql/lib/codeql/rust/security/UseOfHttpExtensions.qll @@ -0,0 +1,60 @@ +/** + * Provides classes and predicates for reasoning about the use of + * non-HTTPS URLs in Rust code. + */ + +import rust +private import codeql.rust.dataflow.DataFlow +private import codeql.rust.dataflow.FlowSink +private import codeql.rust.elements.LiteralExprExt +private import codeql.rust.Concepts + +/** + * Provides default sources, sinks and barriers for detecting use of + * non-HTTPS URLs, as well as extension points for adding your own. + */ +module UseOfHttp { + /** + * A data flow source for use of non-HTTPS URLs. + */ + abstract class Source extends DataFlow::Node { } + + /** + * A data flow sink for use of non-HTTPS URLs. + */ + abstract class Sink extends QuerySink::Range { + override string getSinkType() { result = "UseOfHttp" } + } + + /** + * A barrier for use of non-HTTPS URLs. + */ + abstract class Barrier extends DataFlow::Node { } + + /** + * A string containing an HTTP URL. + */ + class HttpStringLiteral extends StringLiteralExpr { + HttpStringLiteral() { + exists(string s | this.getTextValue() = s | + // Match HTTP URLs that are not private/local + s.regexpMatch("\"http://.*\"") and + not s.regexpMatch("\"http://(localhost|127\\.0\\.0\\.1|192\\.168\\.[0-9]+\\.[0-9]+|10\\.[0-9]+\\.[0-9]+\\.[0-9]+|172\\.16\\.[0-9]+\\.[0-9]+|\\[::1\\]|\\[0:0:0:0:0:0:0:1\\]).*\"") + ) + } + } + + /** + * An HTTP string literal as a source. + */ + private class HttpStringLiteralAsSource extends Source { + HttpStringLiteralAsSource() { this.asExpr().getExpr() instanceof HttpStringLiteral } + } + + /** + * A sink for use of HTTP URLs from model data. + */ + private class ModelsAsDataSink extends Sink { + ModelsAsDataSink() { sinkNode(this, "request-url") } + } +} diff --git a/rust/ql/src/change-notes/2025-09-15-non-https-url.md b/rust/ql/src/change-notes/2025-09-15-non-https-url.md new file mode 100644 index 000000000000..c4ab664f7324 --- /dev/null +++ b/rust/ql/src/change-notes/2025-09-15-non-https-url.md @@ -0,0 +1,4 @@ +--- +category: newQuery +--- +* Added a new query, `rust/non-https-url`, for detecting the use of non-HTTPS URLs that can be intercepted by third parties. \ No newline at end of file diff --git a/rust/ql/src/queries/security/CWE-319/UseOfHttp.qhelp b/rust/ql/src/queries/security/CWE-319/UseOfHttp.qhelp new file mode 100644 index 000000000000..a8ca1d9c7c7e --- /dev/null +++ b/rust/ql/src/queries/security/CWE-319/UseOfHttp.qhelp @@ -0,0 +1,48 @@ + + + + +

Constructing URLs with the HTTP protocol can lead to unsecured connections.

+ +

Furthermore, constructing URLs with the HTTP protocol can create problems if other parts of the +code expect HTTPS URLs. A typical pattern is to use libraries that expect secure connections, +which may fail or fall back to insecure behavior when provided with HTTP URLs instead of HTTPS URLs.

+ +
+ + +

When you construct a URL for network requests, ensure that you use an HTTPS URL rather than an HTTP URL. +Then, any connections that are made using that URL are secure SSL/TLS connections.

+ +
+ + +

The following example shows two ways of making a network request using a URL. When the request is +made using an HTTP URL rather than an HTTPS URL, the connection is unsecured and can be intercepted +by attackers. When the request is made using an HTTPS URL, the connection is a secure SSL/TLS connection.

+ + + +

A better approach is to use HTTPS:

+ + + +
+ + +
  • +OWASP: +Transport Layer Protection Cheat Sheet. +
  • +
  • +OWASP Top 10: +A08:2021 - Software and Data Integrity Failures. +
  • +
  • Rust reqwest documentation: +reqwest crate. +
  • + +
    +
    \ No newline at end of file diff --git a/rust/ql/src/queries/security/CWE-319/UseOfHttp.ql b/rust/ql/src/queries/security/CWE-319/UseOfHttp.ql new file mode 100644 index 000000000000..4a464d90bbe4 --- /dev/null +++ b/rust/ql/src/queries/security/CWE-319/UseOfHttp.ql @@ -0,0 +1,42 @@ +/** + * @name Failure to use HTTPS URLs + * @description Non-HTTPS connections can be intercepted by third parties. + * @kind path-problem + * @problem.severity warning + * @security-severity 8.1 + * @precision high + * @id rust/non-https-url + * @tags security + * external/cwe/cwe-319 + * external/cwe/cwe-345 + */ + +import rust +import codeql.rust.dataflow.DataFlow +import codeql.rust.dataflow.TaintTracking +import codeql.rust.security.UseOfHttpExtensions + +/** + * A taint configuration for HTTP URL strings that flow to URL-using sinks. + */ +module UseOfHttpConfig implements DataFlow::ConfigSig { + import UseOfHttp + + predicate isSource(DataFlow::Node node) { node instanceof Source } + + predicate isSink(DataFlow::Node node) { node instanceof Sink } + + predicate isBarrier(DataFlow::Node barrier) { barrier instanceof Barrier } + + predicate observeDiffInformedIncrementalMode() { any() } +} + +module UseOfHttpFlow = TaintTracking::Global; + +import UseOfHttpFlow::PathGraph + +from UseOfHttpFlow::PathNode sourceNode, UseOfHttpFlow::PathNode sinkNode +where UseOfHttpFlow::flowPath(sourceNode, sinkNode) +select sinkNode.getNode(), sourceNode, sinkNode, + "This URL may be constructed with the HTTP protocol, from $@.", sourceNode.getNode(), + "this HTTP URL" diff --git a/rust/ql/src/queries/security/CWE-319/UseOfHttpBad.rs b/rust/ql/src/queries/security/CWE-319/UseOfHttpBad.rs new file mode 100644 index 000000000000..ada466cae5c0 --- /dev/null +++ b/rust/ql/src/queries/security/CWE-319/UseOfHttpBad.rs @@ -0,0 +1,10 @@ +// BAD: Using HTTP URL which can be intercepted +use reqwest; + +fn main() { + let url = "http://example.com/sensitive-data"; + + // This makes an insecure HTTP request that can be intercepted + let response = reqwest::blocking::get(url).unwrap(); + println!("Response: {}", response.text().unwrap()); +} \ No newline at end of file diff --git a/rust/ql/src/queries/security/CWE-319/UseOfHttpGood.rs b/rust/ql/src/queries/security/CWE-319/UseOfHttpGood.rs new file mode 100644 index 000000000000..22b94235fa17 --- /dev/null +++ b/rust/ql/src/queries/security/CWE-319/UseOfHttpGood.rs @@ -0,0 +1,10 @@ +// GOOD: Using HTTPS URL which provides encryption +use reqwest; + +fn main() { + let url = "https://example.com/sensitive-data"; + + // This makes a secure HTTPS request that is encrypted + let response = reqwest::blocking::get(url).unwrap(); + println!("Response: {}", response.text().unwrap()); +} \ No newline at end of file diff --git a/rust/ql/src/queries/summary/Stats.qll b/rust/ql/src/queries/summary/Stats.qll index 7a1de4f13144..d49e1fdde5d3 100644 --- a/rust/ql/src/queries/summary/Stats.qll +++ b/rust/ql/src/queries/summary/Stats.qll @@ -27,6 +27,7 @@ private import codeql.rust.security.LogInjectionExtensions private import codeql.rust.security.SqlInjectionExtensions private import codeql.rust.security.TaintedPathExtensions private import codeql.rust.security.UncontrolledAllocationSizeExtensions +private import codeql.rust.security.UseOfHttpExtensions private import codeql.rust.security.WeakSensitiveDataHashingExtensions private import codeql.rust.security.HardcodedCryptographicValueExtensions diff --git a/rust/ql/test/query-tests/security/CWE-319/Cargo.lock b/rust/ql/test/query-tests/security/CWE-319/Cargo.lock new file mode 100644 index 000000000000..ad4b5cebd226 --- /dev/null +++ b/rust/ql/test/query-tests/security/CWE-319/Cargo.lock @@ -0,0 +1,1574 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "addr2line" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "backtrace" +version = "0.3.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "windows-targets", +] + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "bitflags" +version = "2.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" + +[[package]] +name = "bumpalo" +version = "3.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" + +[[package]] +name = "bytes" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" + +[[package]] +name = "cc" +version = "1.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65193589c6404eb80b450d618eaf9a2cafaaafd57ecce47370519ef674a7bd44" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "encoding_rs" +version = "0.8.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.0", +] + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "find-msvc-tools" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fd99930f64d146689264c637b5af2f0233a933bef0d8570e2526bf9e083192d" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures-channel" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-io" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" + +[[package]] +name = "futures-sink" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" + +[[package]] +name = "futures-task" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" + +[[package]] +name = "futures-util" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +dependencies = [ + "futures-core", + "futures-io", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "getrandom" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.11.1+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasi 0.14.5+wasi-0.2.4", +] + +[[package]] +name = "gimli" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" + +[[package]] +name = "h2" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3c0b69cfcb4e1b9f1bf2f53f95f766e4661169728ec61cd3fe5a0166f2d1386" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" + +[[package]] +name = "http" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "hyper" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb3aa54a13a0dfe7fbe3a59e0c76093041720fdc77b110cc0fc260fafb4dc51e" +dependencies = [ + "atomic-waker", + "bytes", + "futures-channel", + "futures-core", + "h2", + "http", + "http-body", + "httparse", + "itoa", + "pin-project-lite", + "pin-utils", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" +dependencies = [ + "http", + "hyper", + "hyper-util", + "rustls", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tower-service", +] + +[[package]] +name = "hyper-tls" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" +dependencies = [ + "bytes", + "http-body-util", + "hyper", + "hyper-util", + "native-tls", + "tokio", + "tokio-native-tls", + "tower-service", +] + +[[package]] +name = "hyper-util" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d9b05277c7e8da2c93a568989bb6207bef0112e8d17df7a6eda4a3cf143bc5e" +dependencies = [ + "base64", + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "http", + "http-body", + "hyper", + "ipnet", + "libc", + "percent-encoding", + "pin-project-lite", + "socket2", + "system-configuration", + "tokio", + "tower-service", + "tracing", + "windows-registry", +] + +[[package]] +name = "icu_collections" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" +dependencies = [ + "displaydoc", + "potential_utf", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" + +[[package]] +name = "icu_properties" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "potential_utf", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" + +[[package]] +name = "icu_provider" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" +dependencies = [ + "displaydoc", + "icu_locale_core", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "indexmap" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "206a8042aec68fa4a62e8d3f7aa4ceb508177d9324faf261e1959e495b7a1921" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "io-uring" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "046fa2d4d00aea763528b4950358d0ead425372445dc8ff86312b3c69ff7727b" +dependencies = [ + "bitflags", + "cfg-if", + "libc", +] + +[[package]] +name = "ipnet" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" + +[[package]] +name = "iri-string" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2" +dependencies = [ + "memchr", + "serde", +] + +[[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "js-sys" +version = "0.3.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0b063578492ceec17683ef2f8c5e89121fbd0b172cbc280635ab7567db2738" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "libc" +version = "0.2.175" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543" + +[[package]] +name = "linux-raw-sys" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" + +[[package]] +name = "litemap" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" + +[[package]] +name = "log" +version = "0.4.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" + +[[package]] +name = "memchr" +version = "2.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", +] + +[[package]] +name = "mio" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" +dependencies = [ + "libc", + "wasi 0.11.1+wasi-snapshot-preview1", + "windows-sys 0.59.0", +] + +[[package]] +name = "native-tls" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "object" +version = "0.36.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "openssl" +version = "0.10.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8505734d46c8ab1e19a1dce3aef597ad87dcb4c37e7188231769bd6bd51cebf8" +dependencies = [ + "bitflags", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "openssl-probe" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" + +[[package]] +name = "openssl-sys" +version = "0.9.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + +[[package]] +name = "potential_utf" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84df19adbe5b5a0782edcab45899906947ab039ccf4573713735ee7de1e6b08a" +dependencies = [ + "zerovec", +] + +[[package]] +name = "proc-macro2" +version = "1.0.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "reqwest" +version = "0.12.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d429f34c8092b2d42c7c93cec323bb4adeb7c67698f70839adec842ec10c7ceb" +dependencies = [ + "base64", + "bytes", + "encoding_rs", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-rustls", + "hyper-tls", + "hyper-util", + "js-sys", + "log", + "mime", + "native-tls", + "percent-encoding", + "pin-project-lite", + "rustls-pki-types", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tokio-native-tls", + "tower", + "tower-http", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.16", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" + +[[package]] +name = "rustix" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.61.0", +] + +[[package]] +name = "rustls" +version = "0.23.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0ebcbd2f03de0fc1122ad9bb24b127a5a6cd51d72604a3f3c50ac459762b6cc" +dependencies = [ + "once_cell", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-pki-types" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" +dependencies = [ + "zeroize", +] + +[[package]] +name = "rustls-webpki" +version = "0.103.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5a37813727b78798e53c2bec3f5e8fe12a6d6f8389bf9ca7802add4c9905ad8" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + +[[package]] +name = "schannel" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" +dependencies = [ + "windows-sys 0.61.0", +] + +[[package]] +name = "security-framework" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc1f0cbffaac4852523ce30d8bd3c5cdc873501d96ff467ca09b6767bb8cd5c0" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "serde" +version = "1.0.223" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a505d71960adde88e293da5cb5eda57093379f64e61cf77bf0e6a63af07a7bac" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.223" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20f57cbd357666aa7b3ac84a90b4ea328f1d4ddb6772b430caa5d9e1309bb9e9" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.223" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d428d07faf17e306e699ec1e91996e5a165ba5d6bce5b5155173e91a8a01a56" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.145" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", + "serde_core", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "slab" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "socket2" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807" +dependencies = [ + "libc", + "windows-sys 0.59.0", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "2.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "system-configuration" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" +dependencies = [ + "bitflags", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "tempfile" +version = "3.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84fa4d11fadde498443cca10fd3ac23c951f0dc59e080e9f4b93d4df4e4eea53" +dependencies = [ + "fastrand", + "getrandom 0.3.3", + "once_cell", + "rustix", + "windows-sys 0.61.0", +] + +[[package]] +name = "test" +version = "0.0.1" +dependencies = [ + "reqwest", +] + +[[package]] +name = "tinystr" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tokio" +version = "1.47.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89e49afdadebb872d3145a5638b59eb0691ea23e46ca484037cfab3b76b95038" +dependencies = [ + "backtrace", + "bytes", + "io-uring", + "libc", + "mio", + "pin-project-lite", + "slab", + "socket2", + "windows-sys 0.59.0", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" +dependencies = [ + "rustls", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14307c986784f72ef81c89db7d9e28d6ac26d16213b109ea501696195e6e3ce5" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tower" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper", + "tokio", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-http" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" +dependencies = [ + "bitflags", + "bytes", + "futures-util", + "http", + "http-body", + "iri-string", + "pin-project-lite", + "tower", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +dependencies = [ + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" +dependencies = [ + "once_cell", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "unicode-ident" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "url" +version = "2.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasi" +version = "0.14.5+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4494f6290a82f5fe584817a676a34b9d6763e8d9d18204009fb31dceca98fd4" +dependencies = [ + "wasip2", +] + +[[package]] +name = "wasip2" +version = "1.0.0+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03fa2761397e5bd52002cd7e73110c71af2109aca4e521a9f40473fe685b0a24" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e14915cadd45b529bb8d1f343c4ed0ac1de926144b746e2710f9cd05df6603b" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e28d1ba982ca7923fd01448d5c30c6864d0a14109560296a162f80f305fb93bb" +dependencies = [ + "bumpalo", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.51" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ca85039a9b469b38336411d6d6ced91f3fc87109a2a27b0c197663f5144dffe" +dependencies = [ + "cfg-if", + "js-sys", + "once_cell", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c3d463ae3eff775b0c45df9da45d68837702ac35af998361e2c84e7c5ec1b0d" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bb4ce89b08211f923caf51d527662b75bdc9c9c7aab40f86dcb9fb85ac552aa" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f143854a3b13752c6950862c906306adb27c7e839f7414cec8fea35beab624c1" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "web-sys" +version = "0.3.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77e4b637749ff0d92b8fad63aa1f7cff3cbe125fd49c175cd6345e7272638b12" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "windows-link" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" + +[[package]] +name = "windows-link" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65" + +[[package]] +name = "windows-registry" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b8a9ed28765efc97bbc954883f4e6796c33a06546ebafacbabee9696967499e" +dependencies = [ + "windows-link 0.1.3", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-result" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" +dependencies = [ + "windows-link 0.1.3", +] + +[[package]] +name = "windows-strings" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" +dependencies = [ + "windows-link 0.1.3", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.61.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e201184e40b2ede64bc2ea34968b28e33622acdbbf37104f0e4a33f7abe657aa" +dependencies = [ + "windows-link 0.2.0", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "wit-bindgen" +version = "0.45.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c573471f125075647d03df72e026074b7203790d41351cd6edc96f46bcccd36" + +[[package]] +name = "writeable" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" + +[[package]] +name = "yoke" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerofrom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" + +[[package]] +name = "zerotrie" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7aa2bd55086f1ab526693ecbe444205da57e25f4489879da80635a46d90e73b" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/rust/ql/test/query-tests/security/CWE-319/UseOfHttp.expected b/rust/ql/test/query-tests/security/CWE-319/UseOfHttp.expected new file mode 100644 index 000000000000..53cc8606cc82 --- /dev/null +++ b/rust/ql/test/query-tests/security/CWE-319/UseOfHttp.expected @@ -0,0 +1,78 @@ +#select +| main.rs:12:22:12:43 | ...::get | main.rs:12:45:12:68 | "http://example.com/api" | main.rs:12:22:12:43 | ...::get | This URL may be constructed with the HTTP protocol, from $@. | main.rs:12:45:12:68 | "http://example.com/api" | this HTTP URL | +| main.rs:13:22:13:43 | ...::get | main.rs:13:45:13:73 | "http://api.example.com/data" | main.rs:13:22:13:43 | ...::get | This URL may be constructed with the HTTP protocol, from $@. | main.rs:13:45:13:73 | "http://api.example.com/data" | this HTTP URL | +| main.rs:25:21:25:42 | ...::get | main.rs:22:20:22:39 | "http://example.com" | main.rs:25:21:25:42 | ...::get | This URL may be constructed with the HTTP protocol, from $@. | main.rs:22:20:22:39 | "http://example.com" | this HTTP URL | +| main.rs:36:30:36:51 | ...::get | main.rs:33:20:33:28 | "http://" | main.rs:36:30:36:51 | ...::get | This URL may be constructed with the HTTP protocol, from $@. | main.rs:33:20:33:28 | "http://" | this HTTP URL | +| main.rs:60:21:60:42 | ...::get | main.rs:59:15:59:49 | "http://example.com/sensitive-... | main.rs:60:21:60:42 | ...::get | This URL may be constructed with the HTTP protocol, from $@. | main.rs:59:15:59:49 | "http://example.com/sensitive-... | this HTTP URL | +edges +| main.rs:12:45:12:68 | "http://example.com/api" | main.rs:12:22:12:43 | ...::get | provenance | MaD:1 Sink:MaD:1 | +| main.rs:13:45:13:73 | "http://api.example.com/data" | main.rs:13:22:13:43 | ...::get | provenance | MaD:1 Sink:MaD:1 | +| main.rs:22:9:22:16 | base_url | main.rs:24:28:24:53 | MacroExpr | provenance | | +| main.rs:22:20:22:39 | "http://example.com" | main.rs:22:9:22:16 | base_url | provenance | | +| main.rs:24:9:24:16 | full_url | main.rs:25:45:25:52 | full_url | provenance | | +| main.rs:24:20:24:26 | res | main.rs:24:28:24:53 | { ... } | provenance | | +| main.rs:24:28:24:53 | ...::format(...) | main.rs:24:20:24:26 | res | provenance | | +| main.rs:24:28:24:53 | ...::must_use(...) | main.rs:24:9:24:16 | full_url | provenance | | +| main.rs:24:28:24:53 | MacroExpr | main.rs:24:28:24:53 | ...::format(...) | provenance | MaD:2 | +| main.rs:24:28:24:53 | { ... } | main.rs:24:28:24:53 | ...::must_use(...) | provenance | MaD:3 | +| main.rs:25:44:25:52 | &full_url [&ref] | main.rs:25:21:25:42 | ...::get | provenance | MaD:1 Sink:MaD:1 | +| main.rs:25:45:25:52 | full_url | main.rs:25:44:25:52 | &full_url [&ref] | provenance | | +| main.rs:33:9:33:16 | protocol | main.rs:35:32:35:53 | MacroExpr | provenance | | +| main.rs:33:20:33:28 | "http://" | main.rs:33:9:33:16 | protocol | provenance | | +| main.rs:35:9:35:20 | insecure_url | main.rs:36:54:36:65 | insecure_url | provenance | | +| main.rs:35:24:35:30 | res | main.rs:35:32:35:53 | { ... } | provenance | | +| main.rs:35:32:35:53 | ...::format(...) | main.rs:35:24:35:30 | res | provenance | | +| main.rs:35:32:35:53 | ...::must_use(...) | main.rs:35:9:35:20 | insecure_url | provenance | | +| main.rs:35:32:35:53 | MacroExpr | main.rs:35:32:35:53 | ...::format(...) | provenance | MaD:2 | +| main.rs:35:32:35:53 | { ... } | main.rs:35:32:35:53 | ...::must_use(...) | provenance | MaD:3 | +| main.rs:36:53:36:65 | &insecure_url [&ref] | main.rs:36:30:36:51 | ...::get | provenance | MaD:1 Sink:MaD:1 | +| main.rs:36:54:36:65 | insecure_url | main.rs:36:53:36:65 | &insecure_url [&ref] | provenance | | +| main.rs:59:9:59:11 | url | main.rs:60:44:60:46 | url | provenance | | +| main.rs:59:15:59:49 | "http://example.com/sensitive-... | main.rs:59:9:59:11 | url | provenance | | +| main.rs:60:44:60:46 | url | main.rs:60:21:60:42 | ...::get | provenance | MaD:1 Sink:MaD:1 | +models +| 1 | Sink: reqwest::blocking::get; Argument[0]; request-url | +| 2 | Summary: alloc::fmt::format; Argument[0]; ReturnValue; taint | +| 3 | Summary: core::hint::must_use; Argument[0]; ReturnValue; value | +nodes +| main.rs:12:22:12:43 | ...::get | semmle.label | ...::get | +| main.rs:12:45:12:68 | "http://example.com/api" | semmle.label | "http://example.com/api" | +| main.rs:13:22:13:43 | ...::get | semmle.label | ...::get | +| main.rs:13:45:13:73 | "http://api.example.com/data" | semmle.label | "http://api.example.com/data" | +| main.rs:22:9:22:16 | base_url | semmle.label | base_url | +| main.rs:22:20:22:39 | "http://example.com" | semmle.label | "http://example.com" | +| main.rs:24:9:24:16 | full_url | semmle.label | full_url | +| main.rs:24:20:24:26 | res | semmle.label | res | +| main.rs:24:28:24:53 | ...::format(...) | semmle.label | ...::format(...) | +| main.rs:24:28:24:53 | ...::must_use(...) | semmle.label | ...::must_use(...) | +| main.rs:24:28:24:53 | MacroExpr | semmle.label | MacroExpr | +| main.rs:24:28:24:53 | { ... } | semmle.label | { ... } | +| main.rs:25:21:25:42 | ...::get | semmle.label | ...::get | +| main.rs:25:44:25:52 | &full_url [&ref] | semmle.label | &full_url [&ref] | +| main.rs:25:45:25:52 | full_url | semmle.label | full_url | +| main.rs:33:9:33:16 | protocol | semmle.label | protocol | +| main.rs:33:20:33:28 | "http://" | semmle.label | "http://" | +| main.rs:35:9:35:20 | insecure_url | semmle.label | insecure_url | +| main.rs:35:24:35:30 | res | semmle.label | res | +| main.rs:35:32:35:53 | ...::format(...) | semmle.label | ...::format(...) | +| main.rs:35:32:35:53 | ...::must_use(...) | semmle.label | ...::must_use(...) | +| main.rs:35:32:35:53 | MacroExpr | semmle.label | MacroExpr | +| main.rs:35:32:35:53 | { ... } | semmle.label | { ... } | +| main.rs:36:30:36:51 | ...::get | semmle.label | ...::get | +| main.rs:36:53:36:65 | &insecure_url [&ref] | semmle.label | &insecure_url [&ref] | +| main.rs:36:54:36:65 | insecure_url | semmle.label | insecure_url | +| main.rs:59:9:59:11 | url | semmle.label | url | +| main.rs:59:15:59:49 | "http://example.com/sensitive-... | semmle.label | "http://example.com/sensitive-... | +| main.rs:60:21:60:42 | ...::get | semmle.label | ...::get | +| main.rs:60:44:60:46 | url | semmle.label | url | +subpaths +testFailures +| main.rs:22:20:22:39 | "http://example.com" | Unexpected result: Source | +| main.rs:22:42:22:71 | //... | Missing result: Alert[rust/non-https-url] | +| main.rs:25:21:25:42 | ...::get | Unexpected result: Alert | +| main.rs:33:20:33:28 | "http://" | Unexpected result: Source | +| main.rs:33:31:33:60 | //... | Missing result: Alert[rust/non-https-url] | +| main.rs:36:30:36:51 | ...::get | Unexpected result: Alert | +| main.rs:59:15:59:49 | "http://example.com/sensitive-... | Unexpected result: Source | +| main.rs:59:52:59:81 | //... | Missing result: Alert[rust/non-https-url] | +| main.rs:60:21:60:42 | ...::get | Unexpected result: Alert | diff --git a/rust/ql/test/query-tests/security/CWE-319/UseOfHttp.qlref b/rust/ql/test/query-tests/security/CWE-319/UseOfHttp.qlref new file mode 100644 index 000000000000..90b533300191 --- /dev/null +++ b/rust/ql/test/query-tests/security/CWE-319/UseOfHttp.qlref @@ -0,0 +1,4 @@ +query: queries/security/CWE-319/UseOfHttp.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql \ No newline at end of file diff --git a/rust/ql/test/query-tests/security/CWE-319/main.rs b/rust/ql/test/query-tests/security/CWE-319/main.rs new file mode 100644 index 000000000000..ae58967a49bb --- /dev/null +++ b/rust/ql/test/query-tests/security/CWE-319/main.rs @@ -0,0 +1,65 @@ +use reqwest; +use std::env; + +fn main() { + test_direct_literals(); + test_dynamic_urls(); + test_localhost_exemptions(); +} + +fn test_direct_literals() { + // BAD: Direct HTTP URLs that should be flagged + let _response1 = reqwest::blocking::get("http://example.com/api").unwrap(); // $ Alert[rust/non-https-url] + let _response2 = reqwest::blocking::get("http://api.example.com/data").unwrap(); // $ Alert[rust/non-https-url] + + // GOOD: HTTPS URLs that should not be flagged + let _response3 = reqwest::blocking::get("https://example.com/api").unwrap(); + let _response4 = reqwest::blocking::get("https://api.example.com/data").unwrap(); +} + +fn test_dynamic_urls() { + // BAD: HTTP URLs constructed dynamically + let base_url = "http://example.com"; // $ Alert[rust/non-https-url] + let endpoint = "/api/users"; + let full_url = format!("{}{}", base_url, endpoint); + let _response = reqwest::blocking::get(&full_url).unwrap(); + + // GOOD: HTTPS URLs constructed dynamically + let secure_base = "https://example.com"; + let secure_full = format!("{}{}", secure_base, endpoint); + let _secure_response = reqwest::blocking::get(&secure_full).unwrap(); + + // BAD: HTTP protocol string + let protocol = "http://"; // $ Alert[rust/non-https-url] + let host = "api.example.com"; + let insecure_url = format!("{}{}", protocol, host); + let _insecure_response = reqwest::blocking::get(&insecure_url).unwrap(); + + // GOOD: HTTPS protocol string + let secure_protocol = "https://"; + let secure_url = format!("{}{}", secure_protocol, host); + let _secure_response2 = reqwest::blocking::get(&secure_url).unwrap(); +} + +fn test_localhost_exemptions() { + // GOOD: localhost URLs should not be flagged (local development) + let _local1 = reqwest::blocking::get("http://localhost:8080/api").unwrap(); + let _local2 = reqwest::blocking::get("http://127.0.0.1:3000/test").unwrap(); + let _local3 = reqwest::blocking::get("http://192.168.1.100/internal").unwrap(); + let _local4 = reqwest::blocking::get("http://10.0.0.1/admin").unwrap(); + + // Test IPv6 localhost variants + let _local5 = reqwest::blocking::get("http://[::1]:8080/api").unwrap(); + let _local6 = reqwest::blocking::get("http://[0:0:0:0:0:0:0:1]/test").unwrap(); +} + +// Additional test cases that mirror the Bad/Good examples +fn test_examples() { + // From UseOfHttpBad.rs - BAD case + let url = "http://example.com/sensitive-data"; // $ Alert[rust/non-https-url] + let _response = reqwest::blocking::get(url).unwrap(); + + // From UseOfHttpGood.rs - GOOD case + let secure_url = "https://example.com/sensitive-data"; + let _secure_response = reqwest::blocking::get(secure_url).unwrap(); +} \ No newline at end of file diff --git a/rust/ql/test/query-tests/security/CWE-319/options.yml b/rust/ql/test/query-tests/security/CWE-319/options.yml new file mode 100644 index 000000000000..aa57719603d6 --- /dev/null +++ b/rust/ql/test/query-tests/security/CWE-319/options.yml @@ -0,0 +1,3 @@ +qltest_cargo_check: true +qltest_dependencies: + - reqwest = { version = "0.12.9", features = ["blocking"] } \ No newline at end of file From 7b04cf1a73ddb561738e31ba5b31348ced20c626 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 16 Sep 2025 12:15:44 +0100 Subject: [PATCH 03/12] Rust: Fix up the test annotations. --- .../security/CWE-319/UseOfHttp.expected | 10 ------- .../test/query-tests/security/CWE-319/main.rs | 30 +++++++++---------- 2 files changed, 15 insertions(+), 25 deletions(-) diff --git a/rust/ql/test/query-tests/security/CWE-319/UseOfHttp.expected b/rust/ql/test/query-tests/security/CWE-319/UseOfHttp.expected index 53cc8606cc82..f2a2e7e05f43 100644 --- a/rust/ql/test/query-tests/security/CWE-319/UseOfHttp.expected +++ b/rust/ql/test/query-tests/security/CWE-319/UseOfHttp.expected @@ -66,13 +66,3 @@ nodes | main.rs:60:21:60:42 | ...::get | semmle.label | ...::get | | main.rs:60:44:60:46 | url | semmle.label | url | subpaths -testFailures -| main.rs:22:20:22:39 | "http://example.com" | Unexpected result: Source | -| main.rs:22:42:22:71 | //... | Missing result: Alert[rust/non-https-url] | -| main.rs:25:21:25:42 | ...::get | Unexpected result: Alert | -| main.rs:33:20:33:28 | "http://" | Unexpected result: Source | -| main.rs:33:31:33:60 | //... | Missing result: Alert[rust/non-https-url] | -| main.rs:36:30:36:51 | ...::get | Unexpected result: Alert | -| main.rs:59:15:59:49 | "http://example.com/sensitive-... | Unexpected result: Source | -| main.rs:59:52:59:81 | //... | Missing result: Alert[rust/non-https-url] | -| main.rs:60:21:60:42 | ...::get | Unexpected result: Alert | diff --git a/rust/ql/test/query-tests/security/CWE-319/main.rs b/rust/ql/test/query-tests/security/CWE-319/main.rs index ae58967a49bb..52f744e39a1a 100644 --- a/rust/ql/test/query-tests/security/CWE-319/main.rs +++ b/rust/ql/test/query-tests/security/CWE-319/main.rs @@ -11,30 +11,30 @@ fn test_direct_literals() { // BAD: Direct HTTP URLs that should be flagged let _response1 = reqwest::blocking::get("http://example.com/api").unwrap(); // $ Alert[rust/non-https-url] let _response2 = reqwest::blocking::get("http://api.example.com/data").unwrap(); // $ Alert[rust/non-https-url] - - // GOOD: HTTPS URLs that should not be flagged + + // GOOD: HTTPS URLs that should not be flagged let _response3 = reqwest::blocking::get("https://example.com/api").unwrap(); let _response4 = reqwest::blocking::get("https://api.example.com/data").unwrap(); } fn test_dynamic_urls() { // BAD: HTTP URLs constructed dynamically - let base_url = "http://example.com"; // $ Alert[rust/non-https-url] + let base_url = "http://example.com"; // $ Source let endpoint = "/api/users"; let full_url = format!("{}{}", base_url, endpoint); - let _response = reqwest::blocking::get(&full_url).unwrap(); - + let _response = reqwest::blocking::get(&full_url).unwrap(); // $ Alert[rust/non-https-url] + // GOOD: HTTPS URLs constructed dynamically let secure_base = "https://example.com"; let secure_full = format!("{}{}", secure_base, endpoint); let _secure_response = reqwest::blocking::get(&secure_full).unwrap(); - + // BAD: HTTP protocol string - let protocol = "http://"; // $ Alert[rust/non-https-url] + let protocol = "http://"; // $ Source let host = "api.example.com"; let insecure_url = format!("{}{}", protocol, host); - let _insecure_response = reqwest::blocking::get(&insecure_url).unwrap(); - + let _insecure_response = reqwest::blocking::get(&insecure_url).unwrap(); // $ Alert[rust/non-https-url] + // GOOD: HTTPS protocol string let secure_protocol = "https://"; let secure_url = format!("{}{}", secure_protocol, host); @@ -47,7 +47,7 @@ fn test_localhost_exemptions() { let _local2 = reqwest::blocking::get("http://127.0.0.1:3000/test").unwrap(); let _local3 = reqwest::blocking::get("http://192.168.1.100/internal").unwrap(); let _local4 = reqwest::blocking::get("http://10.0.0.1/admin").unwrap(); - + // Test IPv6 localhost variants let _local5 = reqwest::blocking::get("http://[::1]:8080/api").unwrap(); let _local6 = reqwest::blocking::get("http://[0:0:0:0:0:0:0:1]/test").unwrap(); @@ -56,10 +56,10 @@ fn test_localhost_exemptions() { // Additional test cases that mirror the Bad/Good examples fn test_examples() { // From UseOfHttpBad.rs - BAD case - let url = "http://example.com/sensitive-data"; // $ Alert[rust/non-https-url] - let _response = reqwest::blocking::get(url).unwrap(); - - // From UseOfHttpGood.rs - GOOD case + let url = "http://example.com/sensitive-data"; // $ Source + let _response = reqwest::blocking::get(url).unwrap(); // $ Alert[rust/non-https-url] + + // From UseOfHttpGood.rs - GOOD case let secure_url = "https://example.com/sensitive-data"; let _secure_response = reqwest::blocking::get(secure_url).unwrap(); -} \ No newline at end of file +} From 0924dec545a0eff7113574d629f4c5f2b99007be Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 16 Sep 2025 11:21:57 +0100 Subject: [PATCH 04/12] Rust: Make the tests of the example code closer to the actual example code. --- .../security/CWE-319/UseOfHttp.expected | 16 ++++++++-------- .../test/query-tests/security/CWE-319/main.rs | 18 ++++++++++++++---- 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/rust/ql/test/query-tests/security/CWE-319/UseOfHttp.expected b/rust/ql/test/query-tests/security/CWE-319/UseOfHttp.expected index f2a2e7e05f43..e8b7d3013359 100644 --- a/rust/ql/test/query-tests/security/CWE-319/UseOfHttp.expected +++ b/rust/ql/test/query-tests/security/CWE-319/UseOfHttp.expected @@ -3,7 +3,7 @@ | main.rs:13:22:13:43 | ...::get | main.rs:13:45:13:73 | "http://api.example.com/data" | main.rs:13:22:13:43 | ...::get | This URL may be constructed with the HTTP protocol, from $@. | main.rs:13:45:13:73 | "http://api.example.com/data" | this HTTP URL | | main.rs:25:21:25:42 | ...::get | main.rs:22:20:22:39 | "http://example.com" | main.rs:25:21:25:42 | ...::get | This URL may be constructed with the HTTP protocol, from $@. | main.rs:22:20:22:39 | "http://example.com" | this HTTP URL | | main.rs:36:30:36:51 | ...::get | main.rs:33:20:33:28 | "http://" | main.rs:36:30:36:51 | ...::get | This URL may be constructed with the HTTP protocol, from $@. | main.rs:33:20:33:28 | "http://" | this HTTP URL | -| main.rs:60:21:60:42 | ...::get | main.rs:59:15:59:49 | "http://example.com/sensitive-... | main.rs:60:21:60:42 | ...::get | This URL may be constructed with the HTTP protocol, from $@. | main.rs:59:15:59:49 | "http://example.com/sensitive-... | this HTTP URL | +| main.rs:63:24:63:45 | ...::get | main.rs:60:19:60:53 | "http://example.com/sensitive-... | main.rs:63:24:63:45 | ...::get | This URL may be constructed with the HTTP protocol, from $@. | main.rs:60:19:60:53 | "http://example.com/sensitive-... | this HTTP URL | edges | main.rs:12:45:12:68 | "http://example.com/api" | main.rs:12:22:12:43 | ...::get | provenance | MaD:1 Sink:MaD:1 | | main.rs:13:45:13:73 | "http://api.example.com/data" | main.rs:13:22:13:43 | ...::get | provenance | MaD:1 Sink:MaD:1 | @@ -27,9 +27,9 @@ edges | main.rs:35:32:35:53 | { ... } | main.rs:35:32:35:53 | ...::must_use(...) | provenance | MaD:3 | | main.rs:36:53:36:65 | &insecure_url [&ref] | main.rs:36:30:36:51 | ...::get | provenance | MaD:1 Sink:MaD:1 | | main.rs:36:54:36:65 | insecure_url | main.rs:36:53:36:65 | &insecure_url [&ref] | provenance | | -| main.rs:59:9:59:11 | url | main.rs:60:44:60:46 | url | provenance | | -| main.rs:59:15:59:49 | "http://example.com/sensitive-... | main.rs:59:9:59:11 | url | provenance | | -| main.rs:60:44:60:46 | url | main.rs:60:21:60:42 | ...::get | provenance | MaD:1 Sink:MaD:1 | +| main.rs:60:13:60:15 | url | main.rs:63:47:63:49 | url | provenance | | +| main.rs:60:19:60:53 | "http://example.com/sensitive-... | main.rs:60:13:60:15 | url | provenance | | +| main.rs:63:47:63:49 | url | main.rs:63:24:63:45 | ...::get | provenance | MaD:1 Sink:MaD:1 | models | 1 | Sink: reqwest::blocking::get; Argument[0]; request-url | | 2 | Summary: alloc::fmt::format; Argument[0]; ReturnValue; taint | @@ -61,8 +61,8 @@ nodes | main.rs:36:30:36:51 | ...::get | semmle.label | ...::get | | main.rs:36:53:36:65 | &insecure_url [&ref] | semmle.label | &insecure_url [&ref] | | main.rs:36:54:36:65 | insecure_url | semmle.label | insecure_url | -| main.rs:59:9:59:11 | url | semmle.label | url | -| main.rs:59:15:59:49 | "http://example.com/sensitive-... | semmle.label | "http://example.com/sensitive-... | -| main.rs:60:21:60:42 | ...::get | semmle.label | ...::get | -| main.rs:60:44:60:46 | url | semmle.label | url | +| main.rs:60:13:60:15 | url | semmle.label | url | +| main.rs:60:19:60:53 | "http://example.com/sensitive-... | semmle.label | "http://example.com/sensitive-... | +| main.rs:63:24:63:45 | ...::get | semmle.label | ...::get | +| main.rs:63:47:63:49 | url | semmle.label | url | subpaths diff --git a/rust/ql/test/query-tests/security/CWE-319/main.rs b/rust/ql/test/query-tests/security/CWE-319/main.rs index 52f744e39a1a..cec94840f297 100644 --- a/rust/ql/test/query-tests/security/CWE-319/main.rs +++ b/rust/ql/test/query-tests/security/CWE-319/main.rs @@ -56,10 +56,20 @@ fn test_localhost_exemptions() { // Additional test cases that mirror the Bad/Good examples fn test_examples() { // From UseOfHttpBad.rs - BAD case - let url = "http://example.com/sensitive-data"; // $ Source - let _response = reqwest::blocking::get(url).unwrap(); // $ Alert[rust/non-https-url] + { + let url = "http://example.com/sensitive-data"; // $ Source + + // This makes an insecure HTTP request that can be intercepted + let response = reqwest::blocking::get(url).unwrap(); // $ Alert[rust/non-https-url] + println!("Response: {}", response.text().unwrap()); + } // From UseOfHttpGood.rs - GOOD case - let secure_url = "https://example.com/sensitive-data"; - let _secure_response = reqwest::blocking::get(secure_url).unwrap(); + { + let url = "https://example.com/sensitive-data"; + + // This makes a secure HTTPS request that is encrypted + let response = reqwest::blocking::get(url).unwrap(); + println!("Response: {}", response.text().unwrap()); + } } From 9c7fc583373c353f5bf6cf35d055af3b6f28ad0e Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 16 Sep 2025 12:06:05 +0100 Subject: [PATCH 05/12] Rust: Add tests for a few more edge cases. --- .../security/CWE-319/UseOfHttp.expected | 120 ++++++++++-------- .../test/query-tests/security/CWE-319/main.rs | 22 +++- 2 files changed, 79 insertions(+), 63 deletions(-) diff --git a/rust/ql/test/query-tests/security/CWE-319/UseOfHttp.expected b/rust/ql/test/query-tests/security/CWE-319/UseOfHttp.expected index e8b7d3013359..216d11b36068 100644 --- a/rust/ql/test/query-tests/security/CWE-319/UseOfHttp.expected +++ b/rust/ql/test/query-tests/security/CWE-319/UseOfHttp.expected @@ -1,35 +1,39 @@ #select | main.rs:12:22:12:43 | ...::get | main.rs:12:45:12:68 | "http://example.com/api" | main.rs:12:22:12:43 | ...::get | This URL may be constructed with the HTTP protocol, from $@. | main.rs:12:45:12:68 | "http://example.com/api" | this HTTP URL | -| main.rs:13:22:13:43 | ...::get | main.rs:13:45:13:73 | "http://api.example.com/data" | main.rs:13:22:13:43 | ...::get | This URL may be constructed with the HTTP protocol, from $@. | main.rs:13:45:13:73 | "http://api.example.com/data" | this HTTP URL | -| main.rs:25:21:25:42 | ...::get | main.rs:22:20:22:39 | "http://example.com" | main.rs:25:21:25:42 | ...::get | This URL may be constructed with the HTTP protocol, from $@. | main.rs:22:20:22:39 | "http://example.com" | this HTTP URL | -| main.rs:36:30:36:51 | ...::get | main.rs:33:20:33:28 | "http://" | main.rs:36:30:36:51 | ...::get | This URL may be constructed with the HTTP protocol, from $@. | main.rs:33:20:33:28 | "http://" | this HTTP URL | -| main.rs:63:24:63:45 | ...::get | main.rs:60:19:60:53 | "http://example.com/sensitive-... | main.rs:63:24:63:45 | ...::get | This URL may be constructed with the HTTP protocol, from $@. | main.rs:60:19:60:53 | "http://example.com/sensitive-... | this HTTP URL | +| main.rs:14:22:14:43 | ...::get | main.rs:14:45:14:73 | "http://api.example.com/data" | main.rs:14:22:14:43 | ...::get | This URL may be constructed with the HTTP protocol, from $@. | main.rs:14:45:14:73 | "http://api.example.com/data" | this HTTP URL | +| main.rs:26:21:26:42 | ...::get | main.rs:23:20:23:39 | "http://example.com" | main.rs:26:21:26:42 | ...::get | This URL may be constructed with the HTTP protocol, from $@. | main.rs:23:20:23:39 | "http://example.com" | this HTTP URL | +| main.rs:37:30:37:51 | ...::get | main.rs:34:20:34:28 | "http://" | main.rs:37:30:37:51 | ...::get | This URL may be constructed with the HTTP protocol, from $@. | main.rs:34:20:34:28 | "http://" | this HTTP URL | +| main.rs:53:19:53:40 | ...::get | main.rs:53:42:53:68 | "http://172.31.255.255/bar" | main.rs:53:19:53:40 | ...::get | This URL may be constructed with the HTTP protocol, from $@. | main.rs:53:42:53:68 | "http://172.31.255.255/bar" | this HTTP URL | +| main.rs:60:20:60:41 | ...::get | main.rs:60:43:60:65 | "http://172.32.0.0/baz" | main.rs:60:20:60:41 | ...::get | This URL may be constructed with the HTTP protocol, from $@. | main.rs:60:43:60:65 | "http://172.32.0.0/baz" | this HTTP URL | +| main.rs:71:24:71:45 | ...::get | main.rs:68:19:68:53 | "http://example.com/sensitive-... | main.rs:71:24:71:45 | ...::get | This URL may be constructed with the HTTP protocol, from $@. | main.rs:68:19:68:53 | "http://example.com/sensitive-... | this HTTP URL | edges | main.rs:12:45:12:68 | "http://example.com/api" | main.rs:12:22:12:43 | ...::get | provenance | MaD:1 Sink:MaD:1 | -| main.rs:13:45:13:73 | "http://api.example.com/data" | main.rs:13:22:13:43 | ...::get | provenance | MaD:1 Sink:MaD:1 | -| main.rs:22:9:22:16 | base_url | main.rs:24:28:24:53 | MacroExpr | provenance | | -| main.rs:22:20:22:39 | "http://example.com" | main.rs:22:9:22:16 | base_url | provenance | | -| main.rs:24:9:24:16 | full_url | main.rs:25:45:25:52 | full_url | provenance | | -| main.rs:24:20:24:26 | res | main.rs:24:28:24:53 | { ... } | provenance | | -| main.rs:24:28:24:53 | ...::format(...) | main.rs:24:20:24:26 | res | provenance | | -| main.rs:24:28:24:53 | ...::must_use(...) | main.rs:24:9:24:16 | full_url | provenance | | -| main.rs:24:28:24:53 | MacroExpr | main.rs:24:28:24:53 | ...::format(...) | provenance | MaD:2 | -| main.rs:24:28:24:53 | { ... } | main.rs:24:28:24:53 | ...::must_use(...) | provenance | MaD:3 | -| main.rs:25:44:25:52 | &full_url [&ref] | main.rs:25:21:25:42 | ...::get | provenance | MaD:1 Sink:MaD:1 | -| main.rs:25:45:25:52 | full_url | main.rs:25:44:25:52 | &full_url [&ref] | provenance | | -| main.rs:33:9:33:16 | protocol | main.rs:35:32:35:53 | MacroExpr | provenance | | -| main.rs:33:20:33:28 | "http://" | main.rs:33:9:33:16 | protocol | provenance | | -| main.rs:35:9:35:20 | insecure_url | main.rs:36:54:36:65 | insecure_url | provenance | | -| main.rs:35:24:35:30 | res | main.rs:35:32:35:53 | { ... } | provenance | | -| main.rs:35:32:35:53 | ...::format(...) | main.rs:35:24:35:30 | res | provenance | | -| main.rs:35:32:35:53 | ...::must_use(...) | main.rs:35:9:35:20 | insecure_url | provenance | | -| main.rs:35:32:35:53 | MacroExpr | main.rs:35:32:35:53 | ...::format(...) | provenance | MaD:2 | -| main.rs:35:32:35:53 | { ... } | main.rs:35:32:35:53 | ...::must_use(...) | provenance | MaD:3 | -| main.rs:36:53:36:65 | &insecure_url [&ref] | main.rs:36:30:36:51 | ...::get | provenance | MaD:1 Sink:MaD:1 | -| main.rs:36:54:36:65 | insecure_url | main.rs:36:53:36:65 | &insecure_url [&ref] | provenance | | -| main.rs:60:13:60:15 | url | main.rs:63:47:63:49 | url | provenance | | -| main.rs:60:19:60:53 | "http://example.com/sensitive-... | main.rs:60:13:60:15 | url | provenance | | -| main.rs:63:47:63:49 | url | main.rs:63:24:63:45 | ...::get | provenance | MaD:1 Sink:MaD:1 | +| main.rs:14:45:14:73 | "http://api.example.com/data" | main.rs:14:22:14:43 | ...::get | provenance | MaD:1 Sink:MaD:1 | +| main.rs:23:9:23:16 | base_url | main.rs:25:28:25:53 | MacroExpr | provenance | | +| main.rs:23:20:23:39 | "http://example.com" | main.rs:23:9:23:16 | base_url | provenance | | +| main.rs:25:9:25:16 | full_url | main.rs:26:45:26:52 | full_url | provenance | | +| main.rs:25:20:25:26 | res | main.rs:25:28:25:53 | { ... } | provenance | | +| main.rs:25:28:25:53 | ...::format(...) | main.rs:25:20:25:26 | res | provenance | | +| main.rs:25:28:25:53 | ...::must_use(...) | main.rs:25:9:25:16 | full_url | provenance | | +| main.rs:25:28:25:53 | MacroExpr | main.rs:25:28:25:53 | ...::format(...) | provenance | MaD:2 | +| main.rs:25:28:25:53 | { ... } | main.rs:25:28:25:53 | ...::must_use(...) | provenance | MaD:3 | +| main.rs:26:44:26:52 | &full_url [&ref] | main.rs:26:21:26:42 | ...::get | provenance | MaD:1 Sink:MaD:1 | +| main.rs:26:45:26:52 | full_url | main.rs:26:44:26:52 | &full_url [&ref] | provenance | | +| main.rs:34:9:34:16 | protocol | main.rs:36:32:36:53 | MacroExpr | provenance | | +| main.rs:34:20:34:28 | "http://" | main.rs:34:9:34:16 | protocol | provenance | | +| main.rs:36:9:36:20 | insecure_url | main.rs:37:54:37:65 | insecure_url | provenance | | +| main.rs:36:24:36:30 | res | main.rs:36:32:36:53 | { ... } | provenance | | +| main.rs:36:32:36:53 | ...::format(...) | main.rs:36:24:36:30 | res | provenance | | +| main.rs:36:32:36:53 | ...::must_use(...) | main.rs:36:9:36:20 | insecure_url | provenance | | +| main.rs:36:32:36:53 | MacroExpr | main.rs:36:32:36:53 | ...::format(...) | provenance | MaD:2 | +| main.rs:36:32:36:53 | { ... } | main.rs:36:32:36:53 | ...::must_use(...) | provenance | MaD:3 | +| main.rs:37:53:37:65 | &insecure_url [&ref] | main.rs:37:30:37:51 | ...::get | provenance | MaD:1 Sink:MaD:1 | +| main.rs:37:54:37:65 | insecure_url | main.rs:37:53:37:65 | &insecure_url [&ref] | provenance | | +| main.rs:53:42:53:68 | "http://172.31.255.255/bar" | main.rs:53:19:53:40 | ...::get | provenance | MaD:1 Sink:MaD:1 | +| main.rs:60:43:60:65 | "http://172.32.0.0/baz" | main.rs:60:20:60:41 | ...::get | provenance | MaD:1 Sink:MaD:1 | +| main.rs:68:13:68:15 | url | main.rs:71:47:71:49 | url | provenance | | +| main.rs:68:19:68:53 | "http://example.com/sensitive-... | main.rs:68:13:68:15 | url | provenance | | +| main.rs:71:47:71:49 | url | main.rs:71:24:71:45 | ...::get | provenance | MaD:1 Sink:MaD:1 | models | 1 | Sink: reqwest::blocking::get; Argument[0]; request-url | | 2 | Summary: alloc::fmt::format; Argument[0]; ReturnValue; taint | @@ -37,32 +41,36 @@ models nodes | main.rs:12:22:12:43 | ...::get | semmle.label | ...::get | | main.rs:12:45:12:68 | "http://example.com/api" | semmle.label | "http://example.com/api" | -| main.rs:13:22:13:43 | ...::get | semmle.label | ...::get | -| main.rs:13:45:13:73 | "http://api.example.com/data" | semmle.label | "http://api.example.com/data" | -| main.rs:22:9:22:16 | base_url | semmle.label | base_url | -| main.rs:22:20:22:39 | "http://example.com" | semmle.label | "http://example.com" | -| main.rs:24:9:24:16 | full_url | semmle.label | full_url | -| main.rs:24:20:24:26 | res | semmle.label | res | -| main.rs:24:28:24:53 | ...::format(...) | semmle.label | ...::format(...) | -| main.rs:24:28:24:53 | ...::must_use(...) | semmle.label | ...::must_use(...) | -| main.rs:24:28:24:53 | MacroExpr | semmle.label | MacroExpr | -| main.rs:24:28:24:53 | { ... } | semmle.label | { ... } | -| main.rs:25:21:25:42 | ...::get | semmle.label | ...::get | -| main.rs:25:44:25:52 | &full_url [&ref] | semmle.label | &full_url [&ref] | -| main.rs:25:45:25:52 | full_url | semmle.label | full_url | -| main.rs:33:9:33:16 | protocol | semmle.label | protocol | -| main.rs:33:20:33:28 | "http://" | semmle.label | "http://" | -| main.rs:35:9:35:20 | insecure_url | semmle.label | insecure_url | -| main.rs:35:24:35:30 | res | semmle.label | res | -| main.rs:35:32:35:53 | ...::format(...) | semmle.label | ...::format(...) | -| main.rs:35:32:35:53 | ...::must_use(...) | semmle.label | ...::must_use(...) | -| main.rs:35:32:35:53 | MacroExpr | semmle.label | MacroExpr | -| main.rs:35:32:35:53 | { ... } | semmle.label | { ... } | -| main.rs:36:30:36:51 | ...::get | semmle.label | ...::get | -| main.rs:36:53:36:65 | &insecure_url [&ref] | semmle.label | &insecure_url [&ref] | -| main.rs:36:54:36:65 | insecure_url | semmle.label | insecure_url | -| main.rs:60:13:60:15 | url | semmle.label | url | -| main.rs:60:19:60:53 | "http://example.com/sensitive-... | semmle.label | "http://example.com/sensitive-... | -| main.rs:63:24:63:45 | ...::get | semmle.label | ...::get | -| main.rs:63:47:63:49 | url | semmle.label | url | +| main.rs:14:22:14:43 | ...::get | semmle.label | ...::get | +| main.rs:14:45:14:73 | "http://api.example.com/data" | semmle.label | "http://api.example.com/data" | +| main.rs:23:9:23:16 | base_url | semmle.label | base_url | +| main.rs:23:20:23:39 | "http://example.com" | semmle.label | "http://example.com" | +| main.rs:25:9:25:16 | full_url | semmle.label | full_url | +| main.rs:25:20:25:26 | res | semmle.label | res | +| main.rs:25:28:25:53 | ...::format(...) | semmle.label | ...::format(...) | +| main.rs:25:28:25:53 | ...::must_use(...) | semmle.label | ...::must_use(...) | +| main.rs:25:28:25:53 | MacroExpr | semmle.label | MacroExpr | +| main.rs:25:28:25:53 | { ... } | semmle.label | { ... } | +| main.rs:26:21:26:42 | ...::get | semmle.label | ...::get | +| main.rs:26:44:26:52 | &full_url [&ref] | semmle.label | &full_url [&ref] | +| main.rs:26:45:26:52 | full_url | semmle.label | full_url | +| main.rs:34:9:34:16 | protocol | semmle.label | protocol | +| main.rs:34:20:34:28 | "http://" | semmle.label | "http://" | +| main.rs:36:9:36:20 | insecure_url | semmle.label | insecure_url | +| main.rs:36:24:36:30 | res | semmle.label | res | +| main.rs:36:32:36:53 | ...::format(...) | semmle.label | ...::format(...) | +| main.rs:36:32:36:53 | ...::must_use(...) | semmle.label | ...::must_use(...) | +| main.rs:36:32:36:53 | MacroExpr | semmle.label | MacroExpr | +| main.rs:36:32:36:53 | { ... } | semmle.label | { ... } | +| main.rs:37:30:37:51 | ...::get | semmle.label | ...::get | +| main.rs:37:53:37:65 | &insecure_url [&ref] | semmle.label | &insecure_url [&ref] | +| main.rs:37:54:37:65 | insecure_url | semmle.label | insecure_url | +| main.rs:53:19:53:40 | ...::get | semmle.label | ...::get | +| main.rs:53:42:53:68 | "http://172.31.255.255/bar" | semmle.label | "http://172.31.255.255/bar" | +| main.rs:60:20:60:41 | ...::get | semmle.label | ...::get | +| main.rs:60:43:60:65 | "http://172.32.0.0/baz" | semmle.label | "http://172.32.0.0/baz" | +| main.rs:68:13:68:15 | url | semmle.label | url | +| main.rs:68:19:68:53 | "http://example.com/sensitive-... | semmle.label | "http://example.com/sensitive-... | +| main.rs:71:24:71:45 | ...::get | semmle.label | ...::get | +| main.rs:71:47:71:49 | url | semmle.label | url | subpaths diff --git a/rust/ql/test/query-tests/security/CWE-319/main.rs b/rust/ql/test/query-tests/security/CWE-319/main.rs index cec94840f297..0dd59ce0880e 100644 --- a/rust/ql/test/query-tests/security/CWE-319/main.rs +++ b/rust/ql/test/query-tests/security/CWE-319/main.rs @@ -10,7 +10,8 @@ fn main() { fn test_direct_literals() { // BAD: Direct HTTP URLs that should be flagged let _response1 = reqwest::blocking::get("http://example.com/api").unwrap(); // $ Alert[rust/non-https-url] - let _response2 = reqwest::blocking::get("http://api.example.com/data").unwrap(); // $ Alert[rust/non-https-url] + let _response2 = reqwest::blocking::get("HTTP://EXAMPLE.COM/API").unwrap(); // $ MISSING: Alert[rust/non-https-url] + let _response3 = reqwest::blocking::get("http://api.example.com/data").unwrap(); // $ Alert[rust/non-https-url] // GOOD: HTTPS URLs that should not be flagged let _response3 = reqwest::blocking::get("https://example.com/api").unwrap(); @@ -44,13 +45,20 @@ fn test_dynamic_urls() { fn test_localhost_exemptions() { // GOOD: localhost URLs should not be flagged (local development) let _local1 = reqwest::blocking::get("http://localhost:8080/api").unwrap(); - let _local2 = reqwest::blocking::get("http://127.0.0.1:3000/test").unwrap(); - let _local3 = reqwest::blocking::get("http://192.168.1.100/internal").unwrap(); - let _local4 = reqwest::blocking::get("http://10.0.0.1/admin").unwrap(); + let _local2 = reqwest::blocking::get("HTTP://LOCALHOST:8080/api").unwrap(); + let _local3 = reqwest::blocking::get("http://127.0.0.1:3000/test").unwrap(); + let _local4 = reqwest::blocking::get("http://192.168.1.100/internal").unwrap(); + let _local5 = reqwest::blocking::get("http://10.0.0.1/admin").unwrap(); + let _local6 = reqwest::blocking::get("http://172.16.0.0/foo").unwrap(); + let _local7 = reqwest::blocking::get("http://172.31.255.255/bar").unwrap(); // $ SPURIOUS: Alert[rust/non-https-url] + + // GOOD: test IPv6 localhost variants + let _local8 = reqwest::blocking::get("http://[::1]:8080/api").unwrap(); + let _local9 = reqwest::blocking::get("http://[0:0:0:0:0:0:0:1]/test").unwrap(); + + // BAD: non-private IP address + let _local10 = reqwest::blocking::get("http://172.32.0.0/baz").unwrap(); // $ Alert[rust/non-https-url] - // Test IPv6 localhost variants - let _local5 = reqwest::blocking::get("http://[::1]:8080/api").unwrap(); - let _local6 = reqwest::blocking::get("http://[0:0:0:0:0:0:0:1]/test").unwrap(); } // Additional test cases that mirror the Bad/Good examples From 0f5aa857b874b22bfb53b67b08be2336e14af351 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 16 Sep 2025 11:32:52 +0100 Subject: [PATCH 06/12] Rust: Remove unnecessary import. --- rust/ql/lib/codeql/rust/security/UseOfHttpExtensions.qll | 1 - 1 file changed, 1 deletion(-) diff --git a/rust/ql/lib/codeql/rust/security/UseOfHttpExtensions.qll b/rust/ql/lib/codeql/rust/security/UseOfHttpExtensions.qll index 026880785b6c..8001e6270dd1 100644 --- a/rust/ql/lib/codeql/rust/security/UseOfHttpExtensions.qll +++ b/rust/ql/lib/codeql/rust/security/UseOfHttpExtensions.qll @@ -6,7 +6,6 @@ import rust private import codeql.rust.dataflow.DataFlow private import codeql.rust.dataflow.FlowSink -private import codeql.rust.elements.LiteralExprExt private import codeql.rust.Concepts /** From 80ce55ab1072fb534776fc7b02a93ca6a2b18ce2 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 16 Sep 2025 11:58:23 +0100 Subject: [PATCH 07/12] Rust: Make the private address spaces URL more accurate. --- rust/ql/lib/codeql/rust/security/UseOfHttpExtensions.qll | 2 +- rust/ql/test/query-tests/security/CWE-319/UseOfHttp.expected | 4 ---- rust/ql/test/query-tests/security/CWE-319/main.rs | 2 +- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/rust/ql/lib/codeql/rust/security/UseOfHttpExtensions.qll b/rust/ql/lib/codeql/rust/security/UseOfHttpExtensions.qll index 8001e6270dd1..58466dd0a4fb 100644 --- a/rust/ql/lib/codeql/rust/security/UseOfHttpExtensions.qll +++ b/rust/ql/lib/codeql/rust/security/UseOfHttpExtensions.qll @@ -38,7 +38,7 @@ module UseOfHttp { exists(string s | this.getTextValue() = s | // Match HTTP URLs that are not private/local s.regexpMatch("\"http://.*\"") and - not s.regexpMatch("\"http://(localhost|127\\.0\\.0\\.1|192\\.168\\.[0-9]+\\.[0-9]+|10\\.[0-9]+\\.[0-9]+\\.[0-9]+|172\\.16\\.[0-9]+\\.[0-9]+|\\[::1\\]|\\[0:0:0:0:0:0:0:1\\]).*\"") + not s.regexpMatch("\"http://(localhost|127\\.0\\.0\\.1|192\\.168\\.[0-9]+\\.[0-9]+|10\\.[0-9]+\\.[0-9]+\\.[0-9]+|172\\.(1[6-9]|2[0-9]|3[01])\\.[0-9]+|\\[::1\\]|\\[0:0:0:0:0:0:0:1\\]).*\"") ) } } diff --git a/rust/ql/test/query-tests/security/CWE-319/UseOfHttp.expected b/rust/ql/test/query-tests/security/CWE-319/UseOfHttp.expected index 216d11b36068..ef99b001fcf5 100644 --- a/rust/ql/test/query-tests/security/CWE-319/UseOfHttp.expected +++ b/rust/ql/test/query-tests/security/CWE-319/UseOfHttp.expected @@ -3,7 +3,6 @@ | main.rs:14:22:14:43 | ...::get | main.rs:14:45:14:73 | "http://api.example.com/data" | main.rs:14:22:14:43 | ...::get | This URL may be constructed with the HTTP protocol, from $@. | main.rs:14:45:14:73 | "http://api.example.com/data" | this HTTP URL | | main.rs:26:21:26:42 | ...::get | main.rs:23:20:23:39 | "http://example.com" | main.rs:26:21:26:42 | ...::get | This URL may be constructed with the HTTP protocol, from $@. | main.rs:23:20:23:39 | "http://example.com" | this HTTP URL | | main.rs:37:30:37:51 | ...::get | main.rs:34:20:34:28 | "http://" | main.rs:37:30:37:51 | ...::get | This URL may be constructed with the HTTP protocol, from $@. | main.rs:34:20:34:28 | "http://" | this HTTP URL | -| main.rs:53:19:53:40 | ...::get | main.rs:53:42:53:68 | "http://172.31.255.255/bar" | main.rs:53:19:53:40 | ...::get | This URL may be constructed with the HTTP protocol, from $@. | main.rs:53:42:53:68 | "http://172.31.255.255/bar" | this HTTP URL | | main.rs:60:20:60:41 | ...::get | main.rs:60:43:60:65 | "http://172.32.0.0/baz" | main.rs:60:20:60:41 | ...::get | This URL may be constructed with the HTTP protocol, from $@. | main.rs:60:43:60:65 | "http://172.32.0.0/baz" | this HTTP URL | | main.rs:71:24:71:45 | ...::get | main.rs:68:19:68:53 | "http://example.com/sensitive-... | main.rs:71:24:71:45 | ...::get | This URL may be constructed with the HTTP protocol, from $@. | main.rs:68:19:68:53 | "http://example.com/sensitive-... | this HTTP URL | edges @@ -29,7 +28,6 @@ edges | main.rs:36:32:36:53 | { ... } | main.rs:36:32:36:53 | ...::must_use(...) | provenance | MaD:3 | | main.rs:37:53:37:65 | &insecure_url [&ref] | main.rs:37:30:37:51 | ...::get | provenance | MaD:1 Sink:MaD:1 | | main.rs:37:54:37:65 | insecure_url | main.rs:37:53:37:65 | &insecure_url [&ref] | provenance | | -| main.rs:53:42:53:68 | "http://172.31.255.255/bar" | main.rs:53:19:53:40 | ...::get | provenance | MaD:1 Sink:MaD:1 | | main.rs:60:43:60:65 | "http://172.32.0.0/baz" | main.rs:60:20:60:41 | ...::get | provenance | MaD:1 Sink:MaD:1 | | main.rs:68:13:68:15 | url | main.rs:71:47:71:49 | url | provenance | | | main.rs:68:19:68:53 | "http://example.com/sensitive-... | main.rs:68:13:68:15 | url | provenance | | @@ -65,8 +63,6 @@ nodes | main.rs:37:30:37:51 | ...::get | semmle.label | ...::get | | main.rs:37:53:37:65 | &insecure_url [&ref] | semmle.label | &insecure_url [&ref] | | main.rs:37:54:37:65 | insecure_url | semmle.label | insecure_url | -| main.rs:53:19:53:40 | ...::get | semmle.label | ...::get | -| main.rs:53:42:53:68 | "http://172.31.255.255/bar" | semmle.label | "http://172.31.255.255/bar" | | main.rs:60:20:60:41 | ...::get | semmle.label | ...::get | | main.rs:60:43:60:65 | "http://172.32.0.0/baz" | semmle.label | "http://172.32.0.0/baz" | | main.rs:68:13:68:15 | url | semmle.label | url | diff --git a/rust/ql/test/query-tests/security/CWE-319/main.rs b/rust/ql/test/query-tests/security/CWE-319/main.rs index 0dd59ce0880e..908e6c61c2c1 100644 --- a/rust/ql/test/query-tests/security/CWE-319/main.rs +++ b/rust/ql/test/query-tests/security/CWE-319/main.rs @@ -50,7 +50,7 @@ fn test_localhost_exemptions() { let _local4 = reqwest::blocking::get("http://192.168.1.100/internal").unwrap(); let _local5 = reqwest::blocking::get("http://10.0.0.1/admin").unwrap(); let _local6 = reqwest::blocking::get("http://172.16.0.0/foo").unwrap(); - let _local7 = reqwest::blocking::get("http://172.31.255.255/bar").unwrap(); // $ SPURIOUS: Alert[rust/non-https-url] + let _local7 = reqwest::blocking::get("http://172.31.255.255/bar").unwrap(); // GOOD: test IPv6 localhost variants let _local8 = reqwest::blocking::get("http://[::1]:8080/api").unwrap(); From 4b281fdf12fb8a64cd194aee324ded70855b4695 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 16 Sep 2025 13:02:54 +0100 Subject: [PATCH 08/12] Rust: Use case insensitive regexps. --- rust/ql/lib/codeql/rust/security/UseOfHttpExtensions.qll | 4 ++-- rust/ql/test/query-tests/security/CWE-319/UseOfHttp.expected | 4 ++++ rust/ql/test/query-tests/security/CWE-319/main.rs | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/rust/ql/lib/codeql/rust/security/UseOfHttpExtensions.qll b/rust/ql/lib/codeql/rust/security/UseOfHttpExtensions.qll index 58466dd0a4fb..5e0d534fb7d7 100644 --- a/rust/ql/lib/codeql/rust/security/UseOfHttpExtensions.qll +++ b/rust/ql/lib/codeql/rust/security/UseOfHttpExtensions.qll @@ -37,8 +37,8 @@ module UseOfHttp { HttpStringLiteral() { exists(string s | this.getTextValue() = s | // Match HTTP URLs that are not private/local - s.regexpMatch("\"http://.*\"") and - not s.regexpMatch("\"http://(localhost|127\\.0\\.0\\.1|192\\.168\\.[0-9]+\\.[0-9]+|10\\.[0-9]+\\.[0-9]+\\.[0-9]+|172\\.(1[6-9]|2[0-9]|3[01])\\.[0-9]+|\\[::1\\]|\\[0:0:0:0:0:0:0:1\\]).*\"") + s.regexpMatch("(?i)\"http://.*\"") and + not s.regexpMatch("(?i)\"http://(localhost|127\\.0\\.0\\.1|192\\.168\\.[0-9]+\\.[0-9]+|10\\.[0-9]+\\.[0-9]+\\.[0-9]+|172\\.(1[6-9]|2[0-9]|3[01])\\.[0-9]+|\\[::1\\]|\\[0:0:0:0:0:0:0:1\\]).*\"") ) } } diff --git a/rust/ql/test/query-tests/security/CWE-319/UseOfHttp.expected b/rust/ql/test/query-tests/security/CWE-319/UseOfHttp.expected index ef99b001fcf5..952bd741d1c7 100644 --- a/rust/ql/test/query-tests/security/CWE-319/UseOfHttp.expected +++ b/rust/ql/test/query-tests/security/CWE-319/UseOfHttp.expected @@ -1,5 +1,6 @@ #select | main.rs:12:22:12:43 | ...::get | main.rs:12:45:12:68 | "http://example.com/api" | main.rs:12:22:12:43 | ...::get | This URL may be constructed with the HTTP protocol, from $@. | main.rs:12:45:12:68 | "http://example.com/api" | this HTTP URL | +| main.rs:13:22:13:43 | ...::get | main.rs:13:45:13:68 | "HTTP://EXAMPLE.COM/API" | main.rs:13:22:13:43 | ...::get | This URL may be constructed with the HTTP protocol, from $@. | main.rs:13:45:13:68 | "HTTP://EXAMPLE.COM/API" | this HTTP URL | | main.rs:14:22:14:43 | ...::get | main.rs:14:45:14:73 | "http://api.example.com/data" | main.rs:14:22:14:43 | ...::get | This URL may be constructed with the HTTP protocol, from $@. | main.rs:14:45:14:73 | "http://api.example.com/data" | this HTTP URL | | main.rs:26:21:26:42 | ...::get | main.rs:23:20:23:39 | "http://example.com" | main.rs:26:21:26:42 | ...::get | This URL may be constructed with the HTTP protocol, from $@. | main.rs:23:20:23:39 | "http://example.com" | this HTTP URL | | main.rs:37:30:37:51 | ...::get | main.rs:34:20:34:28 | "http://" | main.rs:37:30:37:51 | ...::get | This URL may be constructed with the HTTP protocol, from $@. | main.rs:34:20:34:28 | "http://" | this HTTP URL | @@ -7,6 +8,7 @@ | main.rs:71:24:71:45 | ...::get | main.rs:68:19:68:53 | "http://example.com/sensitive-... | main.rs:71:24:71:45 | ...::get | This URL may be constructed with the HTTP protocol, from $@. | main.rs:68:19:68:53 | "http://example.com/sensitive-... | this HTTP URL | edges | main.rs:12:45:12:68 | "http://example.com/api" | main.rs:12:22:12:43 | ...::get | provenance | MaD:1 Sink:MaD:1 | +| main.rs:13:45:13:68 | "HTTP://EXAMPLE.COM/API" | main.rs:13:22:13:43 | ...::get | provenance | MaD:1 Sink:MaD:1 | | main.rs:14:45:14:73 | "http://api.example.com/data" | main.rs:14:22:14:43 | ...::get | provenance | MaD:1 Sink:MaD:1 | | main.rs:23:9:23:16 | base_url | main.rs:25:28:25:53 | MacroExpr | provenance | | | main.rs:23:20:23:39 | "http://example.com" | main.rs:23:9:23:16 | base_url | provenance | | @@ -39,6 +41,8 @@ models nodes | main.rs:12:22:12:43 | ...::get | semmle.label | ...::get | | main.rs:12:45:12:68 | "http://example.com/api" | semmle.label | "http://example.com/api" | +| main.rs:13:22:13:43 | ...::get | semmle.label | ...::get | +| main.rs:13:45:13:68 | "HTTP://EXAMPLE.COM/API" | semmle.label | "HTTP://EXAMPLE.COM/API" | | main.rs:14:22:14:43 | ...::get | semmle.label | ...::get | | main.rs:14:45:14:73 | "http://api.example.com/data" | semmle.label | "http://api.example.com/data" | | main.rs:23:9:23:16 | base_url | semmle.label | base_url | diff --git a/rust/ql/test/query-tests/security/CWE-319/main.rs b/rust/ql/test/query-tests/security/CWE-319/main.rs index 908e6c61c2c1..0a3539923da6 100644 --- a/rust/ql/test/query-tests/security/CWE-319/main.rs +++ b/rust/ql/test/query-tests/security/CWE-319/main.rs @@ -10,7 +10,7 @@ fn main() { fn test_direct_literals() { // BAD: Direct HTTP URLs that should be flagged let _response1 = reqwest::blocking::get("http://example.com/api").unwrap(); // $ Alert[rust/non-https-url] - let _response2 = reqwest::blocking::get("HTTP://EXAMPLE.COM/API").unwrap(); // $ MISSING: Alert[rust/non-https-url] + let _response2 = reqwest::blocking::get("HTTP://EXAMPLE.COM/API").unwrap(); // $ Alert[rust/non-https-url] let _response3 = reqwest::blocking::get("http://api.example.com/data").unwrap(); // $ Alert[rust/non-https-url] // GOOD: HTTPS URLs that should not be flagged From 0eb602aad2991216268e79bbe5db05472f2156c0 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 16 Sep 2025 14:00:43 +0100 Subject: [PATCH 09/12] Rust: Update a redirected URL. --- .../src/queries/security/CWE-319/UseOfHttp.qhelp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/rust/ql/src/queries/security/CWE-319/UseOfHttp.qhelp b/rust/ql/src/queries/security/CWE-319/UseOfHttp.qhelp index a8ca1d9c7c7e..a1345b189bb2 100644 --- a/rust/ql/src/queries/security/CWE-319/UseOfHttp.qhelp +++ b/rust/ql/src/queries/security/CWE-319/UseOfHttp.qhelp @@ -6,21 +6,21 @@

    Constructing URLs with the HTTP protocol can lead to unsecured connections.

    -

    Furthermore, constructing URLs with the HTTP protocol can create problems if other parts of the -code expect HTTPS URLs. A typical pattern is to use libraries that expect secure connections, +

    Furthermore, constructing URLs with the HTTP protocol can create problems if other parts of the +code expect HTTPS URLs. A typical pattern is to use libraries that expect secure connections, which may fail or fall back to insecure behavior when provided with HTTP URLs instead of HTTPS URLs.

    -

    When you construct a URL for network requests, ensure that you use an HTTPS URL rather than an HTTP URL. +

    When you construct a URL for network requests, ensure that you use an HTTPS URL rather than an HTTP URL. Then, any connections that are made using that URL are secure SSL/TLS connections.

    -

    The following example shows two ways of making a network request using a URL. When the request is -made using an HTTP URL rather than an HTTPS URL, the connection is unsecured and can be intercepted +

    The following example shows two ways of making a network request using a URL. When the request is +made using an HTTP URL rather than an HTTPS URL, the connection is unsecured and can be intercepted by attackers. When the request is made using an HTTPS URL, the connection is a secure SSL/TLS connection.

    @@ -34,15 +34,15 @@ by attackers. When the request is made using an HTTPS URL, the connection is a s
  • OWASP: -Transport Layer Protection Cheat Sheet. +Transport Layer Security Cheat Sheet.
  • OWASP Top 10: A08:2021 - Software and Data Integrity Failures.
  • -
  • Rust reqwest documentation: +
  • Rust reqwest documentation: reqwest crate.
  • - \ No newline at end of file + From 31bf86fd1bcb60946c038d1329f132647bc60288 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 16 Sep 2025 14:04:47 +0100 Subject: [PATCH 10/12] Rust: Improve the flow around the qhelp example. --- rust/ql/src/queries/security/CWE-319/UseOfHttp.qhelp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/rust/ql/src/queries/security/CWE-319/UseOfHttp.qhelp b/rust/ql/src/queries/security/CWE-319/UseOfHttp.qhelp index a1345b189bb2..e4e0fc5eaa90 100644 --- a/rust/ql/src/queries/security/CWE-319/UseOfHttp.qhelp +++ b/rust/ql/src/queries/security/CWE-319/UseOfHttp.qhelp @@ -19,13 +19,14 @@ Then, any connections that are made using that URL are secure SSL/TLS connection -

    The following example shows two ways of making a network request using a URL. When the request is +

    The following examples show two ways of making a network request using a URL. When the request is made using an HTTP URL rather than an HTTPS URL, the connection is unsecured and can be intercepted -by attackers. When the request is made using an HTTPS URL, the connection is a secure SSL/TLS connection.

    +by attackers:

    -

    A better approach is to use HTTPS:

    +

    A better approach is to use HTTPS. When the request is made using an HTTPS URL, the connection +is a secure SSL/TLS connection:

    From 6f1fcbf41bf7484025a208af19a19630dc3a4df9 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 16 Sep 2025 17:08:22 +0100 Subject: [PATCH 11/12] Rust: Add IPv6 private address range (and explanatory comments). --- rust/ql/lib/codeql/rust/security/UseOfHttpExtensions.qll | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/rust/ql/lib/codeql/rust/security/UseOfHttpExtensions.qll b/rust/ql/lib/codeql/rust/security/UseOfHttpExtensions.qll index 5e0d534fb7d7..bd91cde238f3 100644 --- a/rust/ql/lib/codeql/rust/security/UseOfHttpExtensions.qll +++ b/rust/ql/lib/codeql/rust/security/UseOfHttpExtensions.qll @@ -36,9 +36,12 @@ module UseOfHttp { class HttpStringLiteral extends StringLiteralExpr { HttpStringLiteral() { exists(string s | this.getTextValue() = s | - // Match HTTP URLs that are not private/local + // match HTTP URLs s.regexpMatch("(?i)\"http://.*\"") and - not s.regexpMatch("(?i)\"http://(localhost|127\\.0\\.0\\.1|192\\.168\\.[0-9]+\\.[0-9]+|10\\.[0-9]+\\.[0-9]+\\.[0-9]+|172\\.(1[6-9]|2[0-9]|3[01])\\.[0-9]+|\\[::1\\]|\\[0:0:0:0:0:0:0:1\\]).*\"") + // exclude private/local addresses: + // - IPv4: localhost / 127.0.0.1, 192.168.x.x, 10.x.x.x, 172.16.x.x -> 172.31.x.x + // - IPv6 (address inside []): ::1 (or 0:0:0:0:0:0:0:1), fc00::/7 (i.e. anything beginning `fcxx:` or `fdxx:`) + not s.regexpMatch("(?i)\"http://(localhost|127\\.0\\.0\\.1|192\\.168\\.[0-9]+\\.[0-9]+|10\\.[0-9]+\\.[0-9]+\\.[0-9]+|172\\.(1[6-9]|2[0-9]|3[01])\\.[0-9]+|\\[::1\\]|\\[0:0:0:0:0:0:0:1\\]|\\[f[cd][0-9a-f]{2}:.*\\]).*\"") ) } } From c26a07bb1008a8122e6f39d8df24a128fc4c6e4c Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 19 Sep 2025 16:49:54 +0100 Subject: [PATCH 12/12] Apply suggestions from code review Co-authored-by: Simon Friis Vindum --- rust/ql/src/queries/security/CWE-319/UseOfHttp.qhelp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rust/ql/src/queries/security/CWE-319/UseOfHttp.qhelp b/rust/ql/src/queries/security/CWE-319/UseOfHttp.qhelp index e4e0fc5eaa90..088f202965a9 100644 --- a/rust/ql/src/queries/security/CWE-319/UseOfHttp.qhelp +++ b/rust/ql/src/queries/security/CWE-319/UseOfHttp.qhelp @@ -4,7 +4,7 @@ -

    Constructing URLs with the HTTP protocol can lead to unsecured connections.

    +

    Constructing URLs with the HTTP protocol can lead to insecure connections.

    Furthermore, constructing URLs with the HTTP protocol can create problems if other parts of the code expect HTTPS URLs. A typical pattern is to use libraries that expect secure connections, @@ -14,7 +14,7 @@ which may fail or fall back to insecure behavior when provided with HTTP URLs in

    When you construct a URL for network requests, ensure that you use an HTTPS URL rather than an HTTP URL. -Then, any connections that are made using that URL are secure SSL/TLS connections.

    +Then, any connections that are made using that URL are secure TLS connections.

    @@ -26,7 +26,7 @@ by attackers:

    A better approach is to use HTTPS. When the request is made using an HTTPS URL, the connection -is a secure SSL/TLS connection:

    +is a secure TLS connection: