Compare commits

...

20 Commits

Author SHA1 Message Date
Geoffrey White
a820776f7c Rust: Exclude duplicate results. 2026-06-25 17:44:04 +01:00
Geoffrey White
125fe7b2fa Rust: Add heuristic sinks. 2026-06-25 17:31:39 +01:00
Geoffrey White
37c61982b8 Rust: Add test cases for heuristic sink matching. 2026-06-25 16:27:50 +01:00
Geoffrey White
8e1a7e1789 Rust: Add the new quite to suite lists. 2026-06-25 15:46:03 +01:00
Geoffrey White
ecfd19c506 Rust: Clean up the test file. 2026-06-24 16:32:38 +01:00
Geoffrey White
578c8a2c01 Rust: Make the integer literal decoding more accurate using an existing predicate. 2026-06-24 16:29:20 +01:00
Geoffrey White
4f4271d1f2 Rust: Add a couple more test cases for literal flag values. 2026-06-24 16:20:37 +01:00
Geoffrey White
ae5896416e Rust: Convert sinks to Models As Data, fixing in the process. 2026-06-24 15:40:27 +01:00
Geoffrey White
a322744ee2 Rust: Unstub the constants as well. 2026-06-24 12:49:38 +01:00
Geoffrey White
3523670dd0 Rust: Delete the stubs. 2026-06-24 12:03:29 +01:00
Geoffrey White
2f3bd41216 Rust: Replace stub calls with actual calls. Note that we lose results (likely a models issue). 2026-06-24 11:38:47 +01:00
Geoffrey White
c3bbe94501 Rust: Add libxml dependency. 2026-06-23 17:46:04 +01:00
Geoffrey White
71942b54b3 Merge branch 'main' into copilot/add-xxe-query-for-rust 2026-06-23 17:01:12 +01:00
Geoffrey White
975843889a Rust: Add a test case showing the lack of data flow on flag values. 2026-03-27 18:44:45 +00:00
Geoffrey White
0cb077cd66 Rust: Add test cases for xmlReadFd, xmlCtxtReadFile that were stubbed but not used. 2026-03-27 18:38:52 +00:00
Geoffrey White
bd195e59a5 Rust: Add MaD barriers, since we have that feature now. 2026-03-27 18:37:52 +00:00
Geoffrey White
6f64839305 Merge branch 'main' into copilot/add-xxe-query-for-rust 2026-03-27 18:32:18 +00:00
copilot-swe-agent[bot]
dce8bcdf2b Fix: remove xmlCtxtUseOptions from XXE model (not an XML content sink)
Co-authored-by: geoffw0 <40627776+geoffw0@users.noreply.github.com>
2026-02-20 18:31:49 +00:00
copilot-swe-agent[bot]
eb4d30de7f Add XXE query for Rust (CWE-611)
Co-authored-by: geoffw0 <40627776+geoffw0@users.noreply.github.com>
2026-02-20 18:22:05 +00:00
copilot-swe-agent[bot]
65f74635ca Initial plan 2026-02-20 17:58:21 +00:00
16 changed files with 882 additions and 0 deletions

View File

@@ -19,6 +19,7 @@ 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-327/WeakSensitiveDataHashing.ql
ql/rust/ql/src/queries/security/CWE-611/Xxe.ql
ql/rust/ql/src/queries/security/CWE-614/InsecureCookie.ql
ql/rust/ql/src/queries/security/CWE-770/UncontrolledAllocationSize.ql
ql/rust/ql/src/queries/security/CWE-798/HardcodedCryptographicValue.ql

View File

@@ -20,6 +20,7 @@ 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-327/WeakSensitiveDataHashing.ql
ql/rust/ql/src/queries/security/CWE-611/Xxe.ql
ql/rust/ql/src/queries/security/CWE-614/InsecureCookie.ql
ql/rust/ql/src/queries/security/CWE-696/BadCtorInitialization.ql
ql/rust/ql/src/queries/security/CWE-770/UncontrolledAllocationSize.ql

View File

@@ -20,6 +20,7 @@ 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-327/WeakSensitiveDataHashing.ql
ql/rust/ql/src/queries/security/CWE-611/Xxe.ql
ql/rust/ql/src/queries/security/CWE-614/InsecureCookie.ql
ql/rust/ql/src/queries/security/CWE-770/UncontrolledAllocationSize.ql
ql/rust/ql/src/queries/security/CWE-798/HardcodedCryptographicValue.ql

View File

@@ -0,0 +1,16 @@
extensions:
- addsTo:
pack: codeql/rust-all
extensible: sinkModel
data:
- ["libxml::bindings::xmlReadFile", "Argument[0].Reference", "xxe", "manual"]
- ["libxml::bindings::xmlCtxtReadFile", "Argument[1].Reference", "xxe", "manual"]
- ["libxml::bindings::xmlReadDoc", "Argument[0].Reference", "xxe", "manual"]
- ["libxml::bindings::xmlCtxtReadDoc", "Argument[1].Reference", "xxe", "manual"]
- ["libxml::bindings::xmlReadFd", "Argument[0]", "xxe", "manual"]
- ["libxml::bindings::xmlCtxtReadFd", "Argument[1]", "xxe", "manual"]
- ["libxml::bindings::xmlReadMemory", "Argument[0].Reference", "xxe", "manual"]
- ["libxml::bindings::xmlCtxtReadMemory", "Argument[1].Reference", "xxe", "manual"]
- ["libxml::bindings::xmlReadIO", "Argument[0].Reference", "xxe", "manual"]
- ["libxml::bindings::xmlCtxtReadIO", "Argument[1].Reference", "xxe", "manual"]
- ["libxml::bindings::xmlParseInNodeContext", "Argument[1].Reference", "xxe", "manual"]

View File

@@ -126,6 +126,8 @@ extensions:
# Str
- ["<core::str>::as_str", "Argument[self].Reference", "ReturnValue.Reference", "taint", "manual"]
- ["<core::str>::as_bytes", "Argument[self].Reference", "ReturnValue.Reference", "taint", "manual"]
- ["<core::str>::as_ptr", "Argument[self].Reference", "ReturnValue.Reference", "taint", "manual"]
- ["<core::str>::as_mut_ptr", "Argument[self].Reference", "ReturnValue.Reference", "taint", "manual"]
- ["<core::str>::parse", "Argument[self].Reference", "ReturnValue.Field[core::result::Result::Ok(0)]", "taint", "manual"]
- ["<core::str>::trim", "Argument[self].Reference", "ReturnValue.Reference", "taint", "manual"]
- ["<core::str>::to_string", "Argument[self].Reference", "ReturnValue", "taint", "manual"]

View File

@@ -0,0 +1,110 @@
/**
* Provides classes and predicates to reason about XML external entity (XXE)
* vulnerabilities.
*/
import rust
private import codeql.rust.dataflow.DataFlow
private import codeql.rust.dataflow.FlowBarrier
private import codeql.rust.dataflow.FlowSink
private import codeql.rust.Concepts
private import codeql.rust.dataflow.internal.Node as Node
/**
* Provides default sources, sinks and barriers for detecting XML external
* entity (XXE) vulnerabilities, as well as extension points for adding your
* own.
*/
module Xxe {
/**
* A data flow source for XXE vulnerabilities.
*/
abstract class Source extends DataFlow::Node { }
/**
* A data flow sink for XXE vulnerabilities.
*/
abstract class Sink extends QuerySink::Range {
override string getSinkType() { result = "Xxe" }
}
/**
* A barrier for XXE vulnerabilities.
*/
abstract class Barrier extends DataFlow::Node { }
/**
* An active threat-model source, considered as a flow source.
*/
private class ActiveThreatModelSourceAsSource extends Source, ActiveThreatModelSource { }
/**
* A sink for XXE from model data.
*/
private class ModelsAsDataSink extends Sink {
ModelsAsDataSink() {
exists(Call call |
// an XML parse call
sinkNode(this, "xxe") and
call = this.(Node::FlowSummaryNode).getSinkElement().getCall() and
// with an unsafe option
hasXxeOption(call.getAnArgument(), _)
)
}
}
/**
* A heuristic sink for XXE.
*/
private class HeuristicSink extends Sink {
HeuristicSink() {
exists(Call call |
// a call that looks it might do XML parsing (this is broad)
call.getStaticTarget().getName().getText().regexpMatch("(?i).*(xml|parse).*") and
// with an unsafe option; we require the option to be named (e.g. `XML_PARSE_NOENT`), not a literal value
// (e.g. `2`), to provide additional confidence that we're actually looking at XML parsing)
hasXxeOption(call.getAnArgument(), true) and
// the sink is any input argument
this.asExpr() = call.getAnArgument() and
// don't duplicate modeled sinks
not exists(ModelsAsDataSink s | s.(Node::FlowSummaryNode).getSinkElement().getCall() = call)
)
}
}
/**
* A barrier for XXE vulnerabilities from model data.
*/
private class ModelsAsDataBarrier extends Barrier {
ModelsAsDataBarrier() { barrierNode(this, "xxe") }
}
}
/**
* Holds if `e` is an expression that includes an unsafe `xmlParserOption`,
* specifically `XML_PARSE_NOENT` (value 2, enables entity substitution) or
* `XML_PARSE_DTDLOAD` (value 4, loads external DTD subsets).
*
* `named` is true if the expression is a named constant, false if it is an
* integer literal.
*/
private predicate hasXxeOption(Expr e, boolean named) {
// named constant XML_PARSE_NOENT or XML_PARSE_DTDLOAD (or very similar)
e.(PathExpr).getPath().getText().matches(["%_PARSE_NOENT", "%_PARSE_DTDLOAD"]) and
named = true
or
// integer literal with XML_PARSE_NOENT (bit 1) or XML_PARSE_DTDLOAD (bit 2) set
exists(string value |
e.(IntegerLiteralExpr).getTextValue() = value + concat(e.(IntegerLiteralExpr).getSuffix()) and
value.toInt().bitAnd(6) != 0 // 6 = 2 | 4 = XML_PARSE_NOENT | XML_PARSE_DTDLOAD
) and
named = false
or
// bitwise OR expression
hasXxeOption(e.(BinaryExpr).getLhs(), named)
or
hasXxeOption(e.(BinaryExpr).getRhs(), named)
or
// cast expression (e.g., `XML_PARSE_NOENT as i32`)
hasXxeOption(e.(CastExpr).getExpr(), named)
}

View File

@@ -0,0 +1,4 @@
---
category: newQuery
---
* Added a new query, `rust/xxe`, to detect XML external entity (XXE) vulnerabilities in Rust code that uses the `libxml` crate (bindings to C's `libxml2`). The query flags calls to `libxml2` parsing functions with unsafe options (`XML_PARSE_NOENT` or `XML_PARSE_DTDLOAD`) when the XML input comes from a user-controlled source.

View File

@@ -0,0 +1,50 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>
Parsing XML input with external entity (XXE) expansion enabled while the input
is controlled by a user can lead to a variety of attacks. An attacker who
controls the XML input may be able to use an XML external entity declaration
to read the contents of arbitrary files from the server's file system, perform
server-side request forgery (SSRF), or perform denial-of-service attacks.
</p>
<p>
The Rust <code>libxml</code> crate (bindings to C's <code>libxml2</code>
library) exposes several XML parsing functions that accept a parser options
argument. The options <code>XML_PARSE_NOENT</code> and
<code>XML_PARSE_DTDLOAD</code> enable external entity expansion and loading of
external DTD subsets, respectively. Enabling these options when parsing
user-controlled XML is dangerous.
</p>
</overview>
<recommendation>
<p>
Do not enable <code>XML_PARSE_NOENT</code> or <code>XML_PARSE_DTDLOAD</code>
when parsing user-controlled XML. Parse XML with safe options (for example,
using <code>0</code> as the options argument) to disable external entity
expansion.
</p>
</recommendation>
<example>
<p>
In the following example, the program reads an XML document supplied by the
user and parses it with external entity expansion enabled:
</p>
<sample src="examples/XxeBad.rs"/>
<p>
The following example shows a corrected version that parses with safe options:
</p>
<sample src="examples/XxeGood.rs"/>
</example>
<references>
<li>OWASP: <a href="https://owasp.org/www-community/vulnerabilities/XML_External_Entity_(XXE)_Processing">XML External Entity (XXE) Processing</a>.</li>
<li>CWE: <a href="https://cwe.mitre.org/data/definitions/611.html">CWE-611: Improper Restriction of XML External Entity Reference</a>.</li>
</references>
</qhelp>

View File

@@ -0,0 +1,52 @@
/**
* @name XML external entity expansion
* @description Parsing user-controlled XML with external entity expansion
* enabled may lead to disclosure of confidential data or
* server-side request forgery.
* @kind path-problem
* @problem.severity error
* @security-severity 9.1
* @precision high
* @id rust/xxe
* @tags security
* external/cwe/cwe-611
* external/cwe/cwe-776
* external/cwe/cwe-827
*/
import rust
import codeql.rust.dataflow.DataFlow
import codeql.rust.dataflow.TaintTracking
import codeql.rust.security.XxeExtensions
/**
* A taint configuration for user-controlled data reaching an XML parser with
* external entity expansion enabled.
*/
module XxeConfig implements DataFlow::ConfigSig {
import Xxe
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 isAdditionalFlowStep(DataFlow::Node pred, DataFlow::Node succ) {
// we need flow through casts as a *value* step, not just the default taint step,
// to get flow on reference content when the pointer itself is cast.
pred.asExpr() = succ.asExpr().(CastExpr).getExpr()
}
predicate observeDiffInformedIncrementalMode() { any() }
}
module XxeFlow = TaintTracking::Global<XxeConfig>;
import XxeFlow::PathGraph
from XxeFlow::PathNode sourceNode, XxeFlow::PathNode sinkNode
where XxeFlow::flowPath(sourceNode, sinkNode)
select sinkNode.getNode(), sourceNode, sinkNode,
"XML parsing depends on a $@ without guarding against external entity expansion.",
sourceNode.getNode(), "user-provided value"

View File

@@ -0,0 +1,16 @@
use libxml::bindings::{xmlReadMemory, XML_PARSE_NOENT};
use std::ffi::CString;
fn parse_user_xml(user_input: &str) {
let c_input = CString::new(user_input).unwrap();
// BAD: external entity expansion is enabled via XML_PARSE_NOENT
unsafe {
xmlReadMemory(
c_input.as_ptr(),
c_input.as_bytes().len() as i32,
std::ptr::null(),
std::ptr::null(),
XML_PARSE_NOENT as i32,
);
}
}

View File

@@ -0,0 +1,16 @@
use libxml::bindings::xmlReadMemory;
use std::ffi::CString;
fn parse_user_xml(user_input: &str) {
let c_input = CString::new(user_input).unwrap();
// GOOD: safe options (0) disable external entity expansion
unsafe {
xmlReadMemory(
c_input.as_ptr(),
c_input.as_bytes().len() as i32,
std::ptr::null(),
std::ptr::null(),
0,
);
}
}

View File

@@ -0,0 +1,234 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "aho-corasick"
version = "1.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301"
dependencies = [
"memchr",
]
[[package]]
name = "bindgen"
version = "0.72.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895"
dependencies = [
"bitflags",
"cexpr",
"clang-sys",
"itertools",
"proc-macro2",
"quote",
"regex",
"rustc-hash",
"shlex",
"syn",
]
[[package]]
name = "bitflags"
version = "2.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8"
[[package]]
name = "cexpr"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
dependencies = [
"nom",
]
[[package]]
name = "cfg-if"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
[[package]]
name = "clang-sys"
version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4"
dependencies = [
"glob",
"libc",
"libloading",
]
[[package]]
name = "either"
version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e"
[[package]]
name = "glob"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280"
[[package]]
name = "itertools"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
dependencies = [
"either",
]
[[package]]
name = "libc"
version = "0.2.186"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
[[package]]
name = "libloading"
version = "0.8.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55"
dependencies = [
"cfg-if",
"windows-link",
]
[[package]]
name = "libxml"
version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3e969617eea4e728856e3629229ed5ee92aa0b0a8cc2b7b42171b8a9ba4916e"
dependencies = [
"bindgen",
"libc",
"pkg-config",
"vcpkg",
]
[[package]]
name = "memchr"
version = "2.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88904434abc2901f197fe8cc55f0445e7ded921dba5911dad2e2b39b48e663c4"
[[package]]
name = "minimal-lexical"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[package]]
name = "nom"
version = "7.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
dependencies = [
"memchr",
"minimal-lexical",
]
[[package]]
name = "pkg-config"
version = "0.3.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e"
[[package]]
name = "proc-macro2"
version = "1.0.106"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.46"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfbc457d0c7a0759a614551b11a6409e5951f6c7537be1f1b7682b9ae9230368"
dependencies = [
"proc-macro2",
]
[[package]]
name = "regex"
version = "1.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1292b7759ae1cb9ec195452d1390a074f0cd8541ab7a5a8c31cd6db45d4a6ba"
dependencies = [
"aho-corasick",
"memchr",
"regex-automata",
"regex-syntax",
]
[[package]]
name = "regex-automata"
version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.8.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4"
[[package]]
name = "rustc-hash"
version = "2.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe"
[[package]]
name = "shlex"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
name = "syn"
version = "2.0.118"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "test"
version = "0.0.1"
dependencies = [
"libxml",
]
[[package]]
name = "unicode-ident"
version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
[[package]]
name = "vcpkg"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
[[package]]
name = "windows-link"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"

View File

@@ -0,0 +1,231 @@
#select
| main.rs:9:5:9:27 | ...::xmlReadMemory | main.rs:120:20:120:33 | ...::args | main.rs:9:5:9:27 | ...::xmlReadMemory | XML parsing depends on a $@ without guarding against external entity expansion. | main.rs:120:20:120:33 | ...::args | user-provided value |
| main.rs:14:5:14:27 | ...::xmlReadMemory | main.rs:120:20:120:33 | ...::args | main.rs:14:5:14:27 | ...::xmlReadMemory | XML parsing depends on a $@ without guarding against external entity expansion. | main.rs:120:20:120:33 | ...::args | user-provided value |
| main.rs:19:5:19:27 | ...::xmlReadMemory | main.rs:120:20:120:33 | ...::args | main.rs:19:5:19:27 | ...::xmlReadMemory | XML parsing depends on a $@ without guarding against external entity expansion. | main.rs:120:20:120:33 | ...::args | user-provided value |
| main.rs:24:5:24:25 | ...::xmlReadFile | main.rs:121:25:121:38 | ...::args | main.rs:24:5:24:25 | ...::xmlReadFile | XML parsing depends on a $@ without guarding against external entity expansion. | main.rs:121:25:121:38 | ...::args | user-provided value |
| main.rs:29:5:29:24 | ...::xmlReadDoc | main.rs:120:20:120:33 | ...::args | main.rs:29:5:29:24 | ...::xmlReadDoc | XML parsing depends on a $@ without guarding against external entity expansion. | main.rs:120:20:120:33 | ...::args | user-provided value |
| main.rs:34:5:34:23 | ...::xmlReadFd | main.rs:122:21:122:39 | ...::open | main.rs:34:5:34:23 | ...::xmlReadFd | XML parsing depends on a $@ without guarding against external entity expansion. | main.rs:122:21:122:39 | ...::open | user-provided value |
| main.rs:39:5:39:29 | ...::xmlCtxtReadFile | main.rs:121:25:121:38 | ...::args | main.rs:39:5:39:29 | ...::xmlCtxtReadFile | XML parsing depends on a $@ without guarding against external entity expansion. | main.rs:121:25:121:38 | ...::args | user-provided value |
| main.rs:44:5:44:28 | ...::xmlCtxtReadDoc | main.rs:120:20:120:33 | ...::args | main.rs:44:5:44:28 | ...::xmlCtxtReadDoc | XML parsing depends on a $@ without guarding against external entity expansion. | main.rs:120:20:120:33 | ...::args | user-provided value |
| main.rs:49:5:49:31 | ...::xmlCtxtReadMemory | main.rs:120:20:120:33 | ...::args | main.rs:49:5:49:31 | ...::xmlCtxtReadMemory | XML parsing depends on a $@ without guarding against external entity expansion. | main.rs:120:20:120:33 | ...::args | user-provided value |
| main.rs:61:5:61:27 | ...::xmlReadMemory | main.rs:120:20:120:33 | ...::args | main.rs:61:5:61:27 | ...::xmlReadMemory | XML parsing depends on a $@ without guarding against external entity expansion. | main.rs:120:20:120:33 | ...::args | user-provided value |
| main.rs:64:5:64:27 | ...::xmlReadMemory | main.rs:120:20:120:33 | ...::args | main.rs:64:5:64:27 | ...::xmlReadMemory | XML parsing depends on a $@ without guarding against external entity expansion. | main.rs:120:20:120:33 | ...::args | user-provided value |
| main.rs:111:23:111:30 | user_xml | main.rs:120:20:120:33 | ...::args | main.rs:111:23:111:30 | user_xml | XML parsing depends on a $@ without guarding against external entity expansion. | main.rs:120:20:120:33 | ...::args | user-provided value |
| main.rs:112:23:112:30 | user_xml | main.rs:120:20:120:33 | ...::args | main.rs:112:23:112:30 | user_xml | XML parsing depends on a $@ without guarding against external entity expansion. | main.rs:120:20:120:33 | ...::args | user-provided value |
| main.rs:113:23:113:30 | user_xml | main.rs:120:20:120:33 | ...::args | main.rs:113:23:113:30 | user_xml | XML parsing depends on a $@ without guarding against external entity expansion. | main.rs:120:20:120:33 | ...::args | user-provided value |
edges
| main.rs:7:32:7:45 | ...: ... [&ref] | main.rs:9:29:9:36 | user_xml [&ref] | provenance | |
| main.rs:9:29:9:36 | user_xml [&ref] | main.rs:9:29:9:45 | user_xml.as_ptr() [&ref] | provenance | MaD:15 |
| main.rs:9:29:9:45 | user_xml.as_ptr() [&ref] | main.rs:9:29:9:62 | ... as ... | provenance | |
| main.rs:9:29:9:45 | user_xml.as_ptr() [&ref] | main.rs:9:29:9:62 | ... as ... | provenance | Config |
| main.rs:9:29:9:62 | ... as ... | main.rs:9:5:9:27 | ...::xmlReadMemory | provenance | MaD:7 Sink:MaD:7 |
| main.rs:12:34:12:47 | ...: ... [&ref] | main.rs:14:29:14:36 | user_xml [&ref] | provenance | |
| main.rs:14:29:14:36 | user_xml [&ref] | main.rs:14:29:14:45 | user_xml.as_ptr() [&ref] | provenance | MaD:15 |
| main.rs:14:29:14:45 | user_xml.as_ptr() [&ref] | main.rs:14:29:14:62 | ... as ... | provenance | |
| main.rs:14:29:14:45 | user_xml.as_ptr() [&ref] | main.rs:14:29:14:62 | ... as ... | provenance | Config |
| main.rs:14:29:14:62 | ... as ... | main.rs:14:5:14:27 | ...::xmlReadMemory | provenance | MaD:7 Sink:MaD:7 |
| main.rs:17:35:17:48 | ...: ... [&ref] | main.rs:19:29:19:36 | user_xml [&ref] | provenance | |
| main.rs:19:29:19:36 | user_xml [&ref] | main.rs:19:29:19:45 | user_xml.as_ptr() [&ref] | provenance | MaD:15 |
| main.rs:19:29:19:45 | user_xml.as_ptr() [&ref] | main.rs:19:29:19:62 | ... as ... | provenance | |
| main.rs:19:29:19:45 | user_xml.as_ptr() [&ref] | main.rs:19:29:19:62 | ... as ... | provenance | Config |
| main.rs:19:29:19:62 | ... as ... | main.rs:19:5:19:27 | ...::xmlReadMemory | provenance | MaD:7 Sink:MaD:7 |
| main.rs:22:34:22:52 | ...: ... [&ref] | main.rs:24:27:24:39 | user_filename [&ref] | provenance | |
| main.rs:24:27:24:39 | user_filename [&ref] | main.rs:24:27:24:48 | user_filename.as_ptr() [&ref] | provenance | MaD:15 |
| main.rs:24:27:24:48 | user_filename.as_ptr() [&ref] | main.rs:24:27:24:65 | ... as ... | provenance | |
| main.rs:24:27:24:48 | user_filename.as_ptr() [&ref] | main.rs:24:27:24:65 | ... as ... | provenance | Config |
| main.rs:24:27:24:65 | ... as ... | main.rs:24:5:24:25 | ...::xmlReadFile | provenance | MaD:6 Sink:MaD:6 |
| main.rs:27:33:27:46 | ...: ... [&ref] | main.rs:29:26:29:33 | user_xml [&ref] | provenance | |
| main.rs:29:26:29:33 | user_xml [&ref] | main.rs:29:26:29:42 | user_xml.as_ptr() [&ref] | provenance | MaD:15 |
| main.rs:29:26:29:42 | user_xml.as_ptr() [&ref] | main.rs:29:26:29:60 | ... as ... | provenance | |
| main.rs:29:26:29:42 | user_xml.as_ptr() [&ref] | main.rs:29:26:29:60 | ... as ... | provenance | Config |
| main.rs:29:26:29:60 | ... as ... | main.rs:29:5:29:24 | ...::xmlReadDoc | provenance | MaD:4 Sink:MaD:4 |
| main.rs:32:32:32:43 | ...: i32 [&ref] | main.rs:34:25:34:31 | user_fd [&ref] | provenance | |
| main.rs:34:25:34:31 | user_fd [&ref] | main.rs:34:5:34:23 | ...::xmlReadFd | provenance | MaD:5 Sink:MaD:5 |
| main.rs:37:39:37:57 | ...: ... [&ref] | main.rs:39:53:39:65 | user_filename [&ref] | provenance | |
| main.rs:39:53:39:65 | user_filename [&ref] | main.rs:39:53:39:74 | user_filename.as_ptr() [&ref] | provenance | MaD:15 |
| main.rs:39:53:39:74 | user_filename.as_ptr() [&ref] | main.rs:39:53:39:91 | ... as ... | provenance | |
| main.rs:39:53:39:74 | user_filename.as_ptr() [&ref] | main.rs:39:53:39:91 | ... as ... | provenance | Config |
| main.rs:39:53:39:91 | ... as ... | main.rs:39:5:39:29 | ...::xmlCtxtReadFile | provenance | MaD:2 Sink:MaD:2 |
| main.rs:42:38:42:51 | ...: ... [&ref] | main.rs:44:52:44:59 | user_xml [&ref] | provenance | |
| main.rs:44:52:44:59 | user_xml [&ref] | main.rs:44:52:44:68 | user_xml.as_ptr() [&ref] | provenance | MaD:15 |
| main.rs:44:52:44:68 | user_xml.as_ptr() [&ref] | main.rs:44:52:44:86 | ... as ... | provenance | |
| main.rs:44:52:44:68 | user_xml.as_ptr() [&ref] | main.rs:44:52:44:86 | ... as ... | provenance | Config |
| main.rs:44:52:44:86 | ... as ... | main.rs:44:5:44:28 | ...::xmlCtxtReadDoc | provenance | MaD:1 Sink:MaD:1 |
| main.rs:47:41:47:54 | ...: ... [&ref] | main.rs:51:9:51:16 | user_xml [&ref] | provenance | |
| main.rs:51:9:51:16 | user_xml [&ref] | main.rs:51:9:51:25 | user_xml.as_ptr() [&ref] | provenance | MaD:15 |
| main.rs:51:9:51:25 | user_xml.as_ptr() [&ref] | main.rs:51:9:51:42 | ... as ... | provenance | |
| main.rs:51:9:51:25 | user_xml.as_ptr() [&ref] | main.rs:51:9:51:42 | ... as ... | provenance | Config |
| main.rs:51:9:51:42 | ... as ... | main.rs:49:5:49:31 | ...::xmlCtxtReadMemory | provenance | MaD:3 Sink:MaD:3 |
| main.rs:59:33:59:46 | ...: ... [&ref] | main.rs:61:29:61:36 | user_xml [&ref] | provenance | |
| main.rs:59:33:59:46 | ...: ... [&ref] | main.rs:64:29:64:36 | user_xml [&ref] | provenance | |
| main.rs:61:29:61:36 | user_xml [&ref] | main.rs:61:29:61:45 | user_xml.as_ptr() [&ref] | provenance | MaD:15 |
| main.rs:61:29:61:45 | user_xml.as_ptr() [&ref] | main.rs:61:29:61:62 | ... as ... | provenance | |
| main.rs:61:29:61:45 | user_xml.as_ptr() [&ref] | main.rs:61:29:61:62 | ... as ... | provenance | Config |
| main.rs:61:29:61:62 | ... as ... | main.rs:61:5:61:27 | ...::xmlReadMemory | provenance | MaD:7 Sink:MaD:7 |
| main.rs:64:29:64:36 | user_xml [&ref] | main.rs:64:29:64:45 | user_xml.as_ptr() [&ref] | provenance | MaD:15 |
| main.rs:64:29:64:45 | user_xml.as_ptr() [&ref] | main.rs:64:29:64:62 | ... as ... | provenance | |
| main.rs:64:29:64:45 | user_xml.as_ptr() [&ref] | main.rs:64:29:64:62 | ... as ... | provenance | Config |
| main.rs:64:29:64:62 | ... as ... | main.rs:64:5:64:27 | ...::xmlReadMemory | provenance | MaD:7 Sink:MaD:7 |
| main.rs:109:23:109:36 | ...: ... [&ref] | main.rs:111:23:111:30 | user_xml | provenance | |
| main.rs:109:23:109:36 | ...: ... [&ref] | main.rs:112:23:112:30 | user_xml | provenance | |
| main.rs:109:23:109:36 | ...: ... [&ref] | main.rs:113:23:113:30 | user_xml | provenance | |
| main.rs:120:9:120:16 | user_xml | main.rs:126:31:126:38 | user_xml | provenance | |
| main.rs:120:9:120:16 | user_xml | main.rs:127:33:127:40 | user_xml | provenance | |
| main.rs:120:9:120:16 | user_xml | main.rs:128:34:128:41 | user_xml | provenance | |
| main.rs:120:9:120:16 | user_xml | main.rs:130:32:130:39 | user_xml | provenance | |
| main.rs:120:9:120:16 | user_xml | main.rs:133:37:133:44 | user_xml | provenance | |
| main.rs:120:9:120:16 | user_xml | main.rs:134:40:134:47 | user_xml | provenance | |
| main.rs:120:9:120:16 | user_xml | main.rs:135:32:135:39 | user_xml | provenance | |
| main.rs:120:9:120:16 | user_xml | main.rs:139:29:139:36 | user_xml | provenance | |
| main.rs:120:20:120:33 | ...::args | main.rs:120:20:120:35 | ...::args(...) [element] | provenance | Src:MaD:9 |
| main.rs:120:20:120:35 | ...::args(...) [element] | main.rs:120:20:120:42 | ... .nth(...) [Some] | provenance | MaD:10 |
| main.rs:120:20:120:42 | ... .nth(...) [Some] | main.rs:120:20:120:62 | ... .unwrap_or_default() | provenance | MaD:13 |
| main.rs:120:20:120:62 | ... .unwrap_or_default() | main.rs:120:9:120:16 | user_xml | provenance | |
| main.rs:121:9:121:21 | user_filename | main.rs:129:33:129:45 | user_filename | provenance | |
| main.rs:121:9:121:21 | user_filename | main.rs:132:38:132:50 | user_filename | provenance | |
| main.rs:121:25:121:38 | ...::args | main.rs:121:25:121:40 | ...::args(...) [element] | provenance | Src:MaD:9 |
| main.rs:121:25:121:40 | ...::args(...) [element] | main.rs:121:25:121:47 | ... .nth(...) [Some] | provenance | MaD:10 |
| main.rs:121:25:121:47 | ... .nth(...) [Some] | main.rs:121:25:121:67 | ... .unwrap_or_default() | provenance | MaD:13 |
| main.rs:121:25:121:67 | ... .unwrap_or_default() | main.rs:121:9:121:21 | user_filename | provenance | |
| main.rs:122:9:122:17 | user_file [Some] | main.rs:123:19:123:27 | user_file [Some] | provenance | |
| main.rs:122:21:122:39 | ...::open | main.rs:122:21:122:55 | ...::open(...) [Ok] | provenance | Src:MaD:8 |
| main.rs:122:21:122:55 | ...::open(...) [Ok] | main.rs:122:21:122:60 | ... .ok() [Some] | provenance | MaD:14 |
| main.rs:122:21:122:60 | ... .ok() [Some] | main.rs:122:9:122:17 | user_file [Some] | provenance | |
| main.rs:123:9:123:15 | user_fd [&ref] | main.rs:131:30:131:36 | user_fd [&ref] | provenance | |
| main.rs:123:19:123:27 | user_file [Some] | main.rs:123:19:123:36 | user_file.as_ref() [Some, &ref] | provenance | MaD:11 |
| main.rs:123:19:123:36 | user_file.as_ref() [Some, &ref] | main.rs:123:19:123:72 | ... .map_or(...) [&ref] | provenance | MaD:12 |
| main.rs:123:19:123:72 | ... .map_or(...) [&ref] | main.rs:123:9:123:15 | user_fd [&ref] | provenance | |
| main.rs:126:30:126:38 | &user_xml [&ref] | main.rs:7:32:7:45 | ...: ... [&ref] | provenance | |
| main.rs:126:31:126:38 | user_xml | main.rs:126:30:126:38 | &user_xml [&ref] | provenance | |
| main.rs:127:32:127:40 | &user_xml [&ref] | main.rs:12:34:12:47 | ...: ... [&ref] | provenance | |
| main.rs:127:33:127:40 | user_xml | main.rs:127:32:127:40 | &user_xml [&ref] | provenance | |
| main.rs:128:33:128:41 | &user_xml [&ref] | main.rs:17:35:17:48 | ...: ... [&ref] | provenance | |
| main.rs:128:34:128:41 | user_xml | main.rs:128:33:128:41 | &user_xml [&ref] | provenance | |
| main.rs:129:32:129:45 | &user_filename [&ref] | main.rs:22:34:22:52 | ...: ... [&ref] | provenance | |
| main.rs:129:33:129:45 | user_filename | main.rs:129:32:129:45 | &user_filename [&ref] | provenance | |
| main.rs:130:31:130:39 | &user_xml [&ref] | main.rs:27:33:27:46 | ...: ... [&ref] | provenance | |
| main.rs:130:32:130:39 | user_xml | main.rs:130:31:130:39 | &user_xml [&ref] | provenance | |
| main.rs:131:30:131:36 | user_fd [&ref] | main.rs:32:32:32:43 | ...: i32 [&ref] | provenance | |
| main.rs:132:37:132:50 | &user_filename [&ref] | main.rs:37:39:37:57 | ...: ... [&ref] | provenance | |
| main.rs:132:38:132:50 | user_filename | main.rs:132:37:132:50 | &user_filename [&ref] | provenance | |
| main.rs:133:36:133:44 | &user_xml [&ref] | main.rs:42:38:42:51 | ...: ... [&ref] | provenance | |
| main.rs:133:37:133:44 | user_xml | main.rs:133:36:133:44 | &user_xml [&ref] | provenance | |
| main.rs:134:39:134:47 | &user_xml [&ref] | main.rs:47:41:47:54 | ...: ... [&ref] | provenance | |
| main.rs:134:40:134:47 | user_xml | main.rs:134:39:134:47 | &user_xml [&ref] | provenance | |
| main.rs:135:31:135:39 | &user_xml [&ref] | main.rs:59:33:59:46 | ...: ... [&ref] | provenance | |
| main.rs:135:32:135:39 | user_xml | main.rs:135:31:135:39 | &user_xml [&ref] | provenance | |
| main.rs:139:28:139:36 | &user_xml [&ref] | main.rs:109:23:109:36 | ...: ... [&ref] | provenance | |
| main.rs:139:29:139:36 | user_xml | main.rs:139:28:139:36 | &user_xml [&ref] | provenance | |
models
| 1 | Sink: libxml::bindings::xmlCtxtReadDoc; Argument[1].Reference; xxe |
| 2 | Sink: libxml::bindings::xmlCtxtReadFile; Argument[1].Reference; xxe |
| 3 | Sink: libxml::bindings::xmlCtxtReadMemory; Argument[1].Reference; xxe |
| 4 | Sink: libxml::bindings::xmlReadDoc; Argument[0].Reference; xxe |
| 5 | Sink: libxml::bindings::xmlReadFd; Argument[0]; xxe |
| 6 | Sink: libxml::bindings::xmlReadFile; Argument[0].Reference; xxe |
| 7 | Sink: libxml::bindings::xmlReadMemory; Argument[0].Reference; xxe |
| 8 | Source: <std::fs::File>::open; ReturnValue.Field[core::result::Result::Ok(0)]; file |
| 9 | Source: std::env::args; ReturnValue.Element; commandargs |
| 10 | Summary: <_ as core::iter::traits::iterator::Iterator>::nth; Argument[self].Reference.Element; ReturnValue.Field[core::option::Option::Some(0)]; value |
| 11 | Summary: <core::option::Option>::as_ref; Argument[self].Reference.Field[core::option::Option::Some(0)]; ReturnValue.Field[core::option::Option::Some(0)].Reference; value |
| 12 | Summary: <core::option::Option>::map_or; Argument[self].Field[core::option::Option::Some(0)]; ReturnValue; value |
| 13 | Summary: <core::option::Option>::unwrap_or_default; Argument[self].Field[core::option::Option::Some(0)]; ReturnValue; value |
| 14 | Summary: <core::result::Result>::ok; Argument[self].Field[core::result::Result::Ok(0)]; ReturnValue.Field[core::option::Option::Some(0)]; value |
| 15 | Summary: <core::str>::as_ptr; Argument[self].Reference; ReturnValue.Reference; taint |
nodes
| main.rs:7:32:7:45 | ...: ... [&ref] | semmle.label | ...: ... [&ref] |
| main.rs:9:5:9:27 | ...::xmlReadMemory | semmle.label | ...::xmlReadMemory |
| main.rs:9:29:9:36 | user_xml [&ref] | semmle.label | user_xml [&ref] |
| main.rs:9:29:9:45 | user_xml.as_ptr() [&ref] | semmle.label | user_xml.as_ptr() [&ref] |
| main.rs:9:29:9:62 | ... as ... | semmle.label | ... as ... |
| main.rs:12:34:12:47 | ...: ... [&ref] | semmle.label | ...: ... [&ref] |
| main.rs:14:5:14:27 | ...::xmlReadMemory | semmle.label | ...::xmlReadMemory |
| main.rs:14:29:14:36 | user_xml [&ref] | semmle.label | user_xml [&ref] |
| main.rs:14:29:14:45 | user_xml.as_ptr() [&ref] | semmle.label | user_xml.as_ptr() [&ref] |
| main.rs:14:29:14:62 | ... as ... | semmle.label | ... as ... |
| main.rs:17:35:17:48 | ...: ... [&ref] | semmle.label | ...: ... [&ref] |
| main.rs:19:5:19:27 | ...::xmlReadMemory | semmle.label | ...::xmlReadMemory |
| main.rs:19:29:19:36 | user_xml [&ref] | semmle.label | user_xml [&ref] |
| main.rs:19:29:19:45 | user_xml.as_ptr() [&ref] | semmle.label | user_xml.as_ptr() [&ref] |
| main.rs:19:29:19:62 | ... as ... | semmle.label | ... as ... |
| main.rs:22:34:22:52 | ...: ... [&ref] | semmle.label | ...: ... [&ref] |
| main.rs:24:5:24:25 | ...::xmlReadFile | semmle.label | ...::xmlReadFile |
| main.rs:24:27:24:39 | user_filename [&ref] | semmle.label | user_filename [&ref] |
| main.rs:24:27:24:48 | user_filename.as_ptr() [&ref] | semmle.label | user_filename.as_ptr() [&ref] |
| main.rs:24:27:24:65 | ... as ... | semmle.label | ... as ... |
| main.rs:27:33:27:46 | ...: ... [&ref] | semmle.label | ...: ... [&ref] |
| main.rs:29:5:29:24 | ...::xmlReadDoc | semmle.label | ...::xmlReadDoc |
| main.rs:29:26:29:33 | user_xml [&ref] | semmle.label | user_xml [&ref] |
| main.rs:29:26:29:42 | user_xml.as_ptr() [&ref] | semmle.label | user_xml.as_ptr() [&ref] |
| main.rs:29:26:29:60 | ... as ... | semmle.label | ... as ... |
| main.rs:32:32:32:43 | ...: i32 [&ref] | semmle.label | ...: i32 [&ref] |
| main.rs:34:5:34:23 | ...::xmlReadFd | semmle.label | ...::xmlReadFd |
| main.rs:34:25:34:31 | user_fd [&ref] | semmle.label | user_fd [&ref] |
| main.rs:37:39:37:57 | ...: ... [&ref] | semmle.label | ...: ... [&ref] |
| main.rs:39:5:39:29 | ...::xmlCtxtReadFile | semmle.label | ...::xmlCtxtReadFile |
| main.rs:39:53:39:65 | user_filename [&ref] | semmle.label | user_filename [&ref] |
| main.rs:39:53:39:74 | user_filename.as_ptr() [&ref] | semmle.label | user_filename.as_ptr() [&ref] |
| main.rs:39:53:39:91 | ... as ... | semmle.label | ... as ... |
| main.rs:42:38:42:51 | ...: ... [&ref] | semmle.label | ...: ... [&ref] |
| main.rs:44:5:44:28 | ...::xmlCtxtReadDoc | semmle.label | ...::xmlCtxtReadDoc |
| main.rs:44:52:44:59 | user_xml [&ref] | semmle.label | user_xml [&ref] |
| main.rs:44:52:44:68 | user_xml.as_ptr() [&ref] | semmle.label | user_xml.as_ptr() [&ref] |
| main.rs:44:52:44:86 | ... as ... | semmle.label | ... as ... |
| main.rs:47:41:47:54 | ...: ... [&ref] | semmle.label | ...: ... [&ref] |
| main.rs:49:5:49:31 | ...::xmlCtxtReadMemory | semmle.label | ...::xmlCtxtReadMemory |
| main.rs:51:9:51:16 | user_xml [&ref] | semmle.label | user_xml [&ref] |
| main.rs:51:9:51:25 | user_xml.as_ptr() [&ref] | semmle.label | user_xml.as_ptr() [&ref] |
| main.rs:51:9:51:42 | ... as ... | semmle.label | ... as ... |
| main.rs:59:33:59:46 | ...: ... [&ref] | semmle.label | ...: ... [&ref] |
| main.rs:61:5:61:27 | ...::xmlReadMemory | semmle.label | ...::xmlReadMemory |
| main.rs:61:29:61:36 | user_xml [&ref] | semmle.label | user_xml [&ref] |
| main.rs:61:29:61:45 | user_xml.as_ptr() [&ref] | semmle.label | user_xml.as_ptr() [&ref] |
| main.rs:61:29:61:62 | ... as ... | semmle.label | ... as ... |
| main.rs:64:5:64:27 | ...::xmlReadMemory | semmle.label | ...::xmlReadMemory |
| main.rs:64:29:64:36 | user_xml [&ref] | semmle.label | user_xml [&ref] |
| main.rs:64:29:64:45 | user_xml.as_ptr() [&ref] | semmle.label | user_xml.as_ptr() [&ref] |
| main.rs:64:29:64:62 | ... as ... | semmle.label | ... as ... |
| main.rs:109:23:109:36 | ...: ... [&ref] | semmle.label | ...: ... [&ref] |
| main.rs:111:23:111:30 | user_xml | semmle.label | user_xml |
| main.rs:112:23:112:30 | user_xml | semmle.label | user_xml |
| main.rs:113:23:113:30 | user_xml | semmle.label | user_xml |
| main.rs:120:9:120:16 | user_xml | semmle.label | user_xml |
| main.rs:120:20:120:33 | ...::args | semmle.label | ...::args |
| main.rs:120:20:120:35 | ...::args(...) [element] | semmle.label | ...::args(...) [element] |
| main.rs:120:20:120:42 | ... .nth(...) [Some] | semmle.label | ... .nth(...) [Some] |
| main.rs:120:20:120:62 | ... .unwrap_or_default() | semmle.label | ... .unwrap_or_default() |
| main.rs:121:9:121:21 | user_filename | semmle.label | user_filename |
| main.rs:121:25:121:38 | ...::args | semmle.label | ...::args |
| main.rs:121:25:121:40 | ...::args(...) [element] | semmle.label | ...::args(...) [element] |
| main.rs:121:25:121:47 | ... .nth(...) [Some] | semmle.label | ... .nth(...) [Some] |
| main.rs:121:25:121:67 | ... .unwrap_or_default() | semmle.label | ... .unwrap_or_default() |
| main.rs:122:9:122:17 | user_file [Some] | semmle.label | user_file [Some] |
| main.rs:122:21:122:39 | ...::open | semmle.label | ...::open |
| main.rs:122:21:122:55 | ...::open(...) [Ok] | semmle.label | ...::open(...) [Ok] |
| main.rs:122:21:122:60 | ... .ok() [Some] | semmle.label | ... .ok() [Some] |
| main.rs:123:9:123:15 | user_fd [&ref] | semmle.label | user_fd [&ref] |
| main.rs:123:19:123:27 | user_file [Some] | semmle.label | user_file [Some] |
| main.rs:123:19:123:36 | user_file.as_ref() [Some, &ref] | semmle.label | user_file.as_ref() [Some, &ref] |
| main.rs:123:19:123:72 | ... .map_or(...) [&ref] | semmle.label | ... .map_or(...) [&ref] |
| main.rs:126:30:126:38 | &user_xml [&ref] | semmle.label | &user_xml [&ref] |
| main.rs:126:31:126:38 | user_xml | semmle.label | user_xml |
| main.rs:127:32:127:40 | &user_xml [&ref] | semmle.label | &user_xml [&ref] |
| main.rs:127:33:127:40 | user_xml | semmle.label | user_xml |
| main.rs:128:33:128:41 | &user_xml [&ref] | semmle.label | &user_xml [&ref] |
| main.rs:128:34:128:41 | user_xml | semmle.label | user_xml |
| main.rs:129:32:129:45 | &user_filename [&ref] | semmle.label | &user_filename [&ref] |
| main.rs:129:33:129:45 | user_filename | semmle.label | user_filename |
| main.rs:130:31:130:39 | &user_xml [&ref] | semmle.label | &user_xml [&ref] |
| main.rs:130:32:130:39 | user_xml | semmle.label | user_xml |
| main.rs:131:30:131:36 | user_fd [&ref] | semmle.label | user_fd [&ref] |
| main.rs:132:37:132:50 | &user_filename [&ref] | semmle.label | &user_filename [&ref] |
| main.rs:132:38:132:50 | user_filename | semmle.label | user_filename |
| main.rs:133:36:133:44 | &user_xml [&ref] | semmle.label | &user_xml [&ref] |
| main.rs:133:37:133:44 | user_xml | semmle.label | user_xml |
| main.rs:134:39:134:47 | &user_xml [&ref] | semmle.label | &user_xml [&ref] |
| main.rs:134:40:134:47 | user_xml | semmle.label | user_xml |
| main.rs:135:31:135:39 | &user_xml [&ref] | semmle.label | &user_xml [&ref] |
| main.rs:135:32:135:39 | user_xml | semmle.label | user_xml |
| main.rs:139:28:139:36 | &user_xml [&ref] | semmle.label | &user_xml [&ref] |
| main.rs:139:29:139:36 | user_xml | semmle.label | user_xml |
subpaths

View File

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

View File

@@ -0,0 +1,141 @@
use libxml::bindings;
use std::os::fd::AsRawFd;
use std::os::raw::{c_char, c_uchar};
// --- BAD: user-controlled XML with unsafe parser options ---
unsafe fn test_xml_parse_noent(user_xml: &str) {
// BAD: XML_PARSE_NOENT enables external entity substitution
bindings::xmlReadMemory(user_xml.as_ptr() as *const c_char, user_xml.len() as i32, std::ptr::null_mut(), std::ptr::null_mut(), bindings::xmlParserOption_XML_PARSE_NOENT as i32); // $ Alert[rust/xxe]
}
unsafe fn test_xml_parse_dtdload(user_xml: &str) {
// BAD: XML_PARSE_DTDLOAD enables loading of external DTD subsets
bindings::xmlReadMemory(user_xml.as_ptr() as *const c_char, user_xml.len() as i32, std::ptr::null_mut(), std::ptr::null_mut(), bindings::xmlParserOption_XML_PARSE_DTDLOAD as i32); // $ Alert[rust/xxe]
}
unsafe fn test_xml_parse_combined(user_xml: &str) {
// BAD: combining both unsafe options
bindings::xmlReadMemory(user_xml.as_ptr() as *const c_char, user_xml.len() as i32, std::ptr::null_mut(), std::ptr::null_mut(), bindings::xmlParserOption_XML_PARSE_NOENT as i32 | bindings::xmlParserOption_XML_PARSE_DTDLOAD as i32); // $ Alert[rust/xxe]
}
unsafe fn test_xml_read_file_bad(user_filename: &str) {
// BAD: user-controlled filename with XML_PARSE_NOENT
bindings::xmlReadFile(user_filename.as_ptr() as *const c_char, std::ptr::null_mut(), bindings::xmlParserOption_XML_PARSE_NOENT as i32); // $ Alert[rust/xxe]
}
unsafe fn test_xml_read_doc_bad(user_xml: &str) {
// BAD: user-controlled XML document with XML_PARSE_DTDLOAD
bindings::xmlReadDoc(user_xml.as_ptr() as *const c_uchar, std::ptr::null_mut(), std::ptr::null_mut(), bindings::xmlParserOption_XML_PARSE_DTDLOAD as i32); // $ Alert[rust/xxe]
}
unsafe fn test_xml_read_fd_bad(user_fd: i32) {
// BAD: user-controlled file descriptor with XML_PARSE_DTDLOAD
bindings::xmlReadFd(user_fd, std::ptr::null_mut(), std::ptr::null_mut(), bindings::xmlParserOption_XML_PARSE_DTDLOAD as i32); // $ Alert[rust/xxe]
}
unsafe fn test_xml_ctxt_read_file_bad(user_filename: &str) {
// BAD: user-controlled filename with XML_PARSE_NOENT via ctxt variant
bindings::xmlCtxtReadFile(std::ptr::null_mut(), user_filename.as_ptr() as *const c_char, std::ptr::null_mut(), bindings::xmlParserOption_XML_PARSE_NOENT as i32); // $ Alert[rust/xxe]
}
unsafe fn test_xml_ctxt_read_doc_bad(user_xml: &str) {
// BAD: user-controlled XML with unsafe options via ctxt variant
bindings::xmlCtxtReadDoc(std::ptr::null_mut(), user_xml.as_ptr() as *const c_uchar, std::ptr::null_mut(), std::ptr::null_mut(), bindings::xmlParserOption_XML_PARSE_NOENT as i32); // $ Alert[rust/xxe]
}
unsafe fn test_xml_ctxt_read_memory_bad(user_xml: &str) {
// BAD: user-controlled XML with unsafe options via ctxt variant
bindings::xmlCtxtReadMemory( // $ Alert[rust/xxe]
std::ptr::null_mut(),
user_xml.as_ptr() as *const c_char,
user_xml.len() as i32,
std::ptr::null_mut(),
std::ptr::null_mut(),
bindings::xmlParserOption_XML_PARSE_NOENT as i32,
);
}
unsafe fn test_integer_literals(user_xml: &str) {
// BAD: literal value 2 = XML_PARSE_NOENT
bindings::xmlReadMemory(user_xml.as_ptr() as *const c_char, user_xml.len() as i32, std::ptr::null_mut(), std::ptr::null_mut(), 2); // $ Alert[rust/xxe]
// BAD: literal value 4 = XML_PARSE_DTDLOAD
bindings::xmlReadMemory(user_xml.as_ptr() as *const c_char, user_xml.len() as i32, std::ptr::null_mut(), std::ptr::null_mut(), 4i32); // $ Alert[rust/xxe]
// BAD: literal value 4 = XML_PARSE_DTDLOAD
bindings::xmlReadMemory(user_xml.as_ptr() as *const c_char, user_xml.len() as i32, std::ptr::null_mut(), std::ptr::null_mut(), 0x4i32); // $ MISSING: Alert[rust/xxe]
// GOOD: literal value 0 = no entity expansion
bindings::xmlReadMemory(user_xml.as_ptr() as *const c_char, user_xml.len() as i32, std::ptr::null_mut(), std::ptr::null_mut(), 0);
// GOOD: literal value 2048 = no entity expansion
bindings::xmlReadMemory(user_xml.as_ptr() as *const c_char, user_xml.len() as i32, std::ptr::null_mut(), std::ptr::null_mut(), 2_048);
}
unsafe fn test_dataflow_bad(user_xml: &str) {
// BAD: user-controlled XML with unsafe parser options via dataflow
let flags = bindings::xmlParserOption_XML_PARSE_NOENT as i32 | 1024;
bindings::xmlReadMemory(user_xml.as_ptr() as *const c_char, user_xml.len() as i32, std::ptr::null_mut(), std::ptr::null_mut(), flags); // $ MISSING: Alert[rust/xxe]
}
// --- GOOD: user-controlled XML with safe parser options ---
unsafe fn test_xml_parse_safe_options(user_xml: &str) {
// GOOD: options = 0 means no entity expansion
bindings::xmlReadMemory(user_xml.as_ptr() as *const c_char, user_xml.len() as i32, std::ptr::null_mut(), std::ptr::null_mut(), 0);
bindings::xmlReadFile(user_xml.as_ptr() as *const c_char, std::ptr::null_mut(), 0);
bindings::xmlReadDoc(user_xml.as_ptr() as *const c_uchar, std::ptr::null_mut(), std::ptr::null_mut(), 0);
}
// --- GOOD: hardcoded (non-user-controlled) XML with unsafe parser options ---
unsafe fn test_xml_hardcoded_unsafe() {
let xml = "<root/>";
// GOOD: XML content is not user-controlled
bindings::xmlReadMemory(xml.as_ptr() as *const c_char, xml.len() as i32, std::ptr::null_mut(), std::ptr::null_mut(), bindings::xmlParserOption_XML_PARSE_NOENT as i32);
bindings::xmlReadFile("trusted/input.xml".as_ptr() as *const c_char, std::ptr::null_mut(), bindings::xmlParserOption_XML_PARSE_NOENT as i32);
}
// --- custom parser (requires heuristic match) ---
const XML_PARSE_NOENT: i32 = 2;
const XML_PARSE_DTDLOAD: i32 = 4;
fn custom_xml_parser(xml: &str, options: i32) {
// ...
}
fn test_custom_parser(user_xml: &str) {
custom_xml_parser(user_xml, 0);
custom_xml_parser(user_xml, XML_PARSE_NOENT); // $ Alert[rust/xxe]
custom_xml_parser(user_xml, XML_PARSE_DTDLOAD); // $ Alert[rust/xxe]
custom_xml_parser(user_xml, XML_PARSE_NOENT | XML_PARSE_DTDLOAD); // $ Alert[rust/xxe]
custom_xml_parser("<root/>", XML_PARSE_NOENT | XML_PARSE_DTDLOAD);
}
// ---
fn main() {
let user_xml = std::env::args().nth(1).unwrap_or_default(); // $ Source
let user_filename = std::env::args().nth(2).unwrap_or_default(); // $ Source
let user_file = std::fs::File::open(&user_filename).ok(); // $ Source
let user_fd = user_file.as_ref().map_or(-1, |file| file.as_raw_fd());
unsafe {
test_xml_parse_noent(&user_xml);
test_xml_parse_dtdload(&user_xml);
test_xml_parse_combined(&user_xml);
test_xml_read_file_bad(&user_filename);
test_xml_read_doc_bad(&user_xml);
test_xml_read_fd_bad(user_fd);
test_xml_ctxt_read_file_bad(&user_filename);
test_xml_ctxt_read_doc_bad(&user_xml);
test_xml_ctxt_read_memory_bad(&user_xml);
test_integer_literals(&user_xml);
test_dataflow_bad(&user_xml);
test_xml_parse_safe_options(&user_xml);
test_xml_hardcoded_unsafe();
test_custom_parser(&user_xml);
}
}

View File

@@ -0,0 +1,3 @@
qltest_cargo_check: true
qltest_dependencies:
- libxml = { version = "0.3.8" }