Hacktoberfest 2026: die Issues, die Maintainer für den Oktober markiert haben – offen und einsteigerfreundlich. Hacktoberfest-Issues durchsuchen

Rust: Axum State captured by a closure is treated as remote

Offen
#22,912 1 Kommentar 0 Reaktionen 1 zugewiesene Person Auf GitHub ansehen

Maintainer antworten meist innerhalb von 1 Tag

@hvitved arbeitet bereits daran.

Seit 28.10.2026.

Bewertung

Dieses Issue wurde noch nicht bewertet.

Beschreibung

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-queries 0.1.45; codeql/rust-all 0.2.24.
  • Rust pack build: a1575b98a8cc19bcfa7bb6cb41be688cb3dae65c.
  • Axum 0.8.4; Tokio 1.54.1, with feature rt.
  • Stock rust/path-injection query; 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.

Vorherrschende Sprache
CodeQL
Sterne
10.3k
Forks
2.1k
Ø Merge
2 T. 7 Std.
Gemergte PRs (30 T.)
137

Entwicklungsumgebung

In Codespaces öffnen

Startet den Dev-Container des Projekts im Browser, mit Ihrem eigenen GitHub-Konto.

Erste Schritte

  1. Lesen Sie das ganze Issue und danach den Beitragsleitfaden des Projekts.
  2. Schreiben Sie ins Issue, dass Sie es übernehmen — das erspart doppelte Arbeit.
  3. Forken Sie das Repository und arbeiten Sie in einem Branch.
  4. Öffnen Sie einen Pull Request, der die Issue-Nummer nennt.

Mehr aus github/codeql

Alle Issues in github/codeql

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.