Rust: Axum State captured by a closure is treated as remote
メンテナーはふだん 1 日以内に返信
@hvitved がすでに取り組んでいます。
2026年10月28日 から。
評価
この issue はまだ評価されていません。
説明
Description of the false positive
rust/path-injection reports a configured path from State<Arc<Config>> when the handler destructures State in its parameter and captures the binding in a spawn_blocking closure. The state is initialized with a constant during router construction; it is not request-derived. Reading state.0 into a local Arc clone before the same closure produces no finding. A request-derived Json value captured by the same API correctly produces a finding.
This is a remaining case after github/codeql#22466 and the State field-taint exclusion. That exclusion is already present in the tested library; adding it again would not address this reproduction.
Versions
- CodeQL CLI 2.27.3;
codeql/rust-queries0.1.45;codeql/rust-all0.2.24. - Rust pack build:
a1575b98a8cc19bcfa7bb6cb41be688cb3dae65c. - Axum 0.8.4; Tokio 1.54.1, with feature
rt. - Stock
rust/path-injectionquery; default remote threat model; no custom source, barrier, or suppression model.
Code sample
use axum::{extract::State, routing::{get, post}, Json, Router};
use std::sync::Arc;
struct Config {
path: String,
}
async fn destructured(State(config): State<Arc<Config>>) {
let _ = tokio::task::spawn_blocking(move || std::fs::read_to_string(&config.path)).await;
}
async fn local_clone(state: State<Arc<Config>>) {
let config = Arc::clone(&state.0);
let _ = tokio::task::spawn_blocking(move || std::fs::read_to_string(&config.path)).await;
}
async fn request(Json(path): Json<String>) {
let _ = tokio::task::spawn_blocking(move || std::fs::read_to_string(path)).await;
}
fn main() {
let _: Router = Router::new()
.route("/destructured", get(destructured))
.route("/local-clone", get(local_clone))
.route("/request", post(request))
.with_state(Arc::new(Config { path: String::from("configured-file") }));
}
Expected and observed
| Handler | Expected findings | Observed findings |
|---|---|---|
destructured |
0 | 1 false positive |
local_clone |
0 | 0 |
request |
1 | 1 |
The false-positive path is destructured registration → State parameter → closure capture of config → config.path → std::fs::read_to_string. Only the Json handler should be a remote-to-file finding.
Reproduction with the upstream QL test runner
Place the sample in test.rs in a new test directory below rust/ql/test in a checkout of the codeql-cli/v2.27.3 tag, and add:
# options.yml
qltest_cargo_check: true
qltest_dependencies:
- axum = { version = "=0.8.4" }
- tokio = { version = "=1.54.1", features = ["rt"] }
# TaintedPath.qlref
query: queries/security/CWE-022/TaintedPath.ql
Run codeql test run <test-directory> with the listed packs. The sample compiles and the stock query returns the two findings shown above. A regression expecting only the Json finding fails with the additional State-to-file flow. No scanner or query was disabled.
- 主要言語
- CodeQL
- スター
- 10.3k
- フォーク
- 2.1k
- 平均マージ
- 2日 2時間
- マージ済み PR(30日)
- 123
環境構築
このプロジェクトの開発コンテナを、あなたの GitHub アカウントでブラウザ上に起動します。
- Dockerfile・Docker Compose ファイルなし
- プルリクエストのテンプレートなし
- コントリビューションガイドを読む
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
github/codeql のほかの issue
-
JavaScript externs model StorageEvent() with no type argument対応中かも @asgerf が 11 日前に担当しました。 オープンfalse-positive javascript
難易度 2/5 1〜3時間 初心者へのやさしさ 84/100
github/codeql#22632 · コメント 3 件 · リアクション 1 件 · 担当者 2 名 ·
メンテナーはふだん 1 日以内に返信
-
Add AlertSuppression.ql for Rust (inline // codeql[...] suppression)対応中かも @cnuss が 212 日前に担当しました。 オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
github/codeql#21637 · コメント 2 件 ·
メンテナーはふだん 1 日以内に返信
-
false-positive
難易度 2/5 1〜3時間 初心者へのやさしさ 70/100
github/codeql#21076 · コメント 3 件 · リアクション 3 件 ·
メンテナーはふだん 1 日以内に返信
-
java/unsafe-double-checked-locking: missed when the field is re-read through a call that returns itオープン
難易度 4/5 3〜5日 初心者へのやさしさ 25/100
メンテナーはふだん 1 日以内に返信
-
java/unsafe-double-checked-locking: not reported when the outer guard is written as !(!(x == null))オープン
難易度 4/5 3〜5日 初心者へのやさしさ 42/100
メンテナーはふだん 1 日以内に返信