VYPR
High severityNVD Advisory· Published Feb 6, 2026· Updated Feb 6, 2026

Qdrant affected by arbitrary file write via `/logger` endpoint

CVE-2026-25628

Description

Qdrant is a vector similarity search engine and vector database. From 1.9.3 to before 1.16.0, it is possible to append to arbitrary files via /logger endpoint using an attacker-controlled on_disk.log_file path. Minimal privileges are required (read-only access). This vulnerability is fixed in 1.16.0.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
qdrantcrates.io
>= 1.9.3, < 1.15.61.15.6

Affected products

1

Patches

1
32b7fdfb7f54

Restrict `/logger` API (#7527)

https://github.com/qdrant/qdrantRoman TitovNov 13, 2025via ghsa
3 files changed · +41 12
  • src/actix/api/service_api.rs+28 10 modified
    @@ -140,26 +140,44 @@ fn kubernetes_healthz() -> impl Responder {
     }
     
     #[get("/logger")]
    -async fn get_logger_config(handle: web::Data<tracing::LoggerHandle>) -> impl Responder {
    +async fn get_logger_config(
    +    ActixAccess(access): ActixAccess,
    +    handle: web::Data<tracing::LoggerHandle>,
    +) -> impl Responder {
         let timing = Instant::now();
    -    let result = handle.get_config().await;
    -    helpers::process_response(Ok(result), timing, None)
    +
    +    let future = async {
    +        let _ = access.check_global_access(AccessRequirements::new())?;
    +        let config = handle.get_config().await;
    +        Ok(config)
    +    };
    +
    +    helpers::process_response(future.await, timing, None)
     }
     
     #[post("/logger")]
     async fn update_logger_config(
    +    ActixAccess(access): ActixAccess,
         handle: web::Data<tracing::LoggerHandle>,
    -    config: web::Json<tracing::LoggerConfig>,
    +    mut config: web::Json<tracing::LoggerConfig>,
     ) -> impl Responder {
         let timing = Instant::now();
     
    -    let result = handle
    -        .update_config(config.into_inner())
    -        .await
    -        .map(|_| true)
    -        .map_err(|err| StorageError::service_error(err.to_string()));
    +    let future = async {
    +        let _ = access.check_global_access(AccessRequirements::new().manage())?;
    +
    +        // Log file can only be set in Qdrant config file
    +        config.on_disk.log_file = None;
    +
    +        handle
    +            .update_config(config.into_inner())
    +            .await
    +            .map_err(|err| StorageError::service_error(err.to_string()))?;
    +
    +        Ok(true)
    +    };
     
    -    helpers::process_response(result, timing, None)
    +    helpers::process_response(future.await, timing, None)
     }
     
     // Configure services
    
  • src/tracing/on_disk.rs+4 2 modified
    @@ -71,14 +71,16 @@ where
         }
     
         let Some(log_file) = &config.log_file else {
    -        return Err(anyhow::format_err!("log file is not specified"));
    +        return Err(anyhow::format_err!(
    +            "log file is not specified (it can only be specified in the config file)"
    +        ));
         };
     
         let writer = fs::OpenOptions::new()
             .create(true)
             .append(true)
             .open(log_file)
    -        .with_context(|| format!("failed to open {log_file} log-file"))?;
    +        .with_context(|| format!("failed to open log file {log_file}"))?;
     
         let layer = fmt::Layer::default()
             .with_writer(Mutex::new(io::BufWriter::with_capacity(
    
  • tests/consensus_tests/auth_tests/test_jwt_access.py+9 0 modified
    @@ -566,6 +566,8 @@ def __init__(self, r, coll_rw, m, rest_endpoint, grpc_endpoint=None, **kwargs):
         "metrics": EndpointAccess(True, False, True, "GET /metrics", coll_r=False),
         "get_issues": EndpointAccess(True, True, True, "GET /issues"),
         "clear_issues": EndpointAccess(False, False, True, "DELETE /issues"),
    +    "get_logger_config": EndpointAccess(True, False, True, "GET /logger", coll_r=False),
    +    "update_logger_config": EndpointAccess(False, False, True, "POST /logger"),
     }
     
     
    @@ -1864,3 +1866,10 @@ def test_get_issues():
     
     def test_clear_issues():
         check_access("clear_issues")
    +
    +
    +def test_get_logger_config():
    +    check_access("get_logger_config")
    +
    +def test_update_logger_config():
    +    check_access("update_logger_config", {})
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

5

News mentions

0

No linked articles in our index yet.