Saltar al contenido principal
WebguneWebgunebeta
Precios
Toutes les failles

MoyenneCVE-2026-11669127 de octubre de 2026

MLflow CrewAI autologging enregistre les clés API du fournisseur de LLM dans les spans de trace enregistrés

Exploitable dans des cas précis ou avec un impact limité : à corriger à la prochaine mise à jour.

Sévérité
Moyenne6.5 / 10
Publiée le
27 de octubre de 2026
Mise à jour
27 de octubre de 2026

L'avis

Traduction automatique de l'avis officiel. En cas de doute, l'avis d'origine, plus bas, fait foi.

Résumé

mlflow.crewai.autolog() communique les clés API du fournisseur de LLM CrewAI dans la télémétrie de trace MLflow.

Lorsqu'un Agent CrewAI est instrumenté avec l'autologging MLflow, MLflow sérialise le __dict__ de l'agent et convertit ses champs en chaînes de caractères. Le champ llm contient l'objet CrewAI LLM, dont la représentation chaîne inclut sa api_key en clair.

En conséquence, une application qui appelle mlflow.crewai.autolog() peut envoyer involontairement sa clé API du fournisseur de LLM vers le backend de trace MLflow ou la destination OTLP configurée.

L'application n'a pas besoin d'enregistrer explicitement le credential ou de le placer dans un attribut de span. Le credential est extrait automatiquement par l'instrumentation MLflow.

Cela a été vérifié sur MLflow 3.16.0 avec CrewAI 1.15.18 en utilisant l'exportateur OTLP de MLflow. Le credential factice est apparu dans 5 emplacements d'attributs sur 2 spans.

Détails

Le problème principal se trouve dans :

mlflow/crewai/autolog.py::_get_agent_attributes()

La fonction parcourt le Agent.__dict__ CrewAI et convertit les champs de l'agent en chaînes. tools et embedder bénéficient d'un traitement particulier, mais les objets contenant des credentials tels que les suivants ne sont pas nettoyés :

  • llm
  • function_calling_llm
  • agent_executor
  • crew

Par exemple, agent.llm est un objet CrewAI LLM. Dans CrewAI 1.15.18, le modèle LLM sous-jacent contient api_key comme champ normal. Sa représentation chaîne contient donc le credential :

llm_type='openai' model='gpt-4.1-mini' ... api_key='sk-proj-...' ...

MLflow stocke ensuite cette chaîne comme attribut de span.

Il y a une indication importante que c'est une divulgation non intentionnelle : l'extraction d'attribut LLM dédiée de MLflow exclut déjà explicitement api_key dans _get_llm_attributes(). Le span LLM ne révèle donc pas le credential, tandis que la sérialisation __dict__ Agent plus large contourne cette protection.

Il y a également un deuxième chemin de sérialisation indépendant dans :

mlflow/crewai/autolog.py::_construct_full_inputs()

Ce code utilise :

v.__dict__ if hasattr(v, "__dict__") else v

sur les arguments d'appel. Lors de l'exécution CrewAI, l'objet Agent est passé en argument, ce qui entraîne l'expansion de son __dict__ et l'inclusion de l'objet LLM contenant le credential dans mlflow.spanInputs.

Par conséquent, il y a deux chemins de fuite indépendants :

  1. Attributs de span Agent via _get_agent_attributes()
  2. Entrées de span via _construct_full_inputs()

La correction de seulement la sérialisation des attributs Agent laisserait le chemin mlflow.spanInputs vulnérable.

Une approche plus sûre serait d'éviter la sérialisation récursive des valeurs __dict__ d'objets arbitraires. La télémétrie Agent devrait utiliser une liste explicite de champs scalaires non sensibles, et les objets contenant des credentials tels que llm, function_calling_llm, agent_executor et crew devraient soit être réduits à des métadonnées soit être omis.

De même, _construct_full_inputs() ne devrait pas automatiquement étendre les objets arbitraires via __dict__, ou les valeurs résulantes devraient passer par le même mécanisme de nettoyage avant d'être attachées à un span.

Preuve de concept

Environnement :

MLflow: 3.16.0
CrewAI: 1.15.18
Python: 3.12.3
opentelemetry-exporter-otlp-proto-http: 1.42.1
1. Preuve de sérialisation directe

La démonstration suivante montre la vulnérabilité sans démarrer un Crew, sans faire une requête réseau et sans nécessiter un serveur MLflow :

import importlib
from crewai import LLM, Agent

autolog = importlib.import_module("mlflow.crewai.autolog")

llm = LLM(
    model="gpt-4.1-mini",
    api_key="sk-proj-EXAMPLE1234567890",
)

agent = Agent(
    role="r",
    goal="g",
    backstory="b",
    llm=llm,
)

attrs = autolog._get_agent_attributes(agent)

assert "sk-proj-EXAMPLE1234567890" in attrs["llm"]

print(attrs["llm"])

La sortie contient la clé API en clair, par exemple :

llm_type='openai' model='gpt-4.1-mini' ... api_key='sk-proj-EXAMPLE1234567890' ...

Aucune requête fournisseur n'est nécessaire.

2. Divulgation de trace de bout en bout

La vulnérabilité peut également être reproduite avec l'exportateur OTLP de MLflow.

Configurez un récepteur OTLP HTTP local et définissez :

export OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=http://127.0.0.1:4318/v1/traces
export OTEL_EXPORTER_OTLP_TRACES_PROTOCOL=http/protobuf
export CREWAI_DISABLE_TELEMETRY=true

Puis exécutez :

import mlflow

from crewai import Agent, Crew, LLM, Task

mlflow.crewai.autolog()

llm = LLM(
    model="gpt-4.1-mini",
    api_key="sk-proj-EXAMPLE1234567890",
)

agent = Agent(
    role="Support Responder",
    goal="Answer support questions",
    backstory="A support agent",
    llm=llm,
)

task = Task(
    description="Answer the user's question",
    expected_output="A response",
    agent=agent,
)

crew = Crew(
    agents=[agent],
    tasks=[task],
)

crew.kickoff()

Un récepteur OTLP local peut décoder le ExportTraceServiceRequest envoyé par MLflow.

La requête fournisseur est censée échouer car le credential est intentionnellement factice. Cela n'affecte pas la vulnérabilité : la valeur sensible est ajoutée au span MLflow lorsque l'instrumentation commence, avant que la requête fournisseur ne réussisse ou n'échoue.

Dans l'environnement testé, la clé API factice est apparue dans la télémétrie exportée à 5 emplacements sur 2 spans, y compris :

Support Responder
  attributes.llm
  attributes.function_calling_llm
  attributes.agent_executor
  attributes.mlflow.spanInputs

Task.execute_sync
  attributes.mlflow.spanInputs

La valeur capturée est produite par le chemin de télémétrie/export réel de MLflow et non insérée manuellement dans un span.

Tous les credentials utilisés dans la reproduction sont des valeurs factices générées localement. Aucun credential d'API réel n'est nécessaire.

Impact

Type : Divulgation d'information sensible / Divulgation de credential CWE : CWE-532 — Insertion of Sensitive Information into Log File

La suite de l'avis n'est pas traduite : elle figure dans l'avis d'origine, plus bas.

Composants touchés

ComposantVersions touchéesCorrigé en
mlflowPython (pip)>= 2.19.0, < 3.17.03.17.0

Vous utilisez une version touchée ? Passez à la version corrigée, puis redéployez.

MLflow CrewAI autologging records LLM provider API keys in logged trace spans

Summary

mlflow.crewai.autolog() leaks CrewAI LLM provider API keys into MLflow trace telemetry.

When a CrewAI Agent is instrumented with MLflow autologging, MLflow serializes the agent's __dict__ and converts its fields to strings. The llm field contains the CrewAI LLM object, whose string representation includes its api_key in plaintext.

As a result, an application that calls mlflow.crewai.autolog() can unintentionally send its LLM provider API key to the MLflow trace backend or configured OTLP destination.

The application does not need to explicitly log the credential or place it in a span attribute. The credential is extracted automatically by MLflow's instrumentation.

This was verified on MLflow 3.16.0 with CrewAI 1.15.18 using MLflow's own OTLP exporter. The fake credential appeared in 5 attribute locations across 2 spans.

Details

The primary issue is in:

mlflow/crewai/autolog.py::_get_agent_attributes()

The function walks the CrewAI Agent.__dict__ and converts agent fields to strings. tools and embedder receive special handling, but credential-bearing objects such as the following are not sanitized:

  • llm
  • function_calling_llm
  • agent_executor
  • crew

For example, agent.llm is a CrewAI LLM object. In CrewAI 1.15.18, the underlying LLM model contains api_key as a normal field. Its string representation therefore contains the credential:

llm_type='openai' model='gpt-4.1-mini' ... api_key='sk-proj-...' ...

MLflow subsequently stores this string as a span attribute.

There is an important indication that this is an unintended disclosure: MLflow's dedicated LLM attribute extraction already explicitly excludes api_key in _get_llm_attributes(). The LLM span therefore does not expose the credential, while the broader Agent __dict__ serialization bypasses that protection.

There is also a second, independent serialization path in:

mlflow/crewai/autolog.py::_construct_full_inputs()

This code uses:

v.__dict__ if hasattr(v, "__dict__") else v

on call arguments. During CrewAI execution, the Agent object is passed as an argument, causing its __dict__ to be expanded and the credential-bearing LLM object to be included in mlflow.spanInputs.

Therefore, there are two independent leakage paths:

  1. Agent span attributes through _get_agent_attributes()
  2. Span inputs through _construct_full_inputs()

Fixing only the Agent attribute serialization would leave the mlflow.spanInputs path vulnerable.

A safer approach would be to avoid recursively serializing arbitrary object __dict__ values. Agent telemetry should use an explicit allowlist of non-sensitive scalar fields, and credential-bearing objects such as llm, function_calling_llm, agent_executor, and crew should either be reduced to safe metadata or omitted.

Similarly, _construct_full_inputs() should not automatically expand arbitrary objects through __dict__, or the resulting values should pass through the same sanitization mechanism before being attached to a span.

PoC

Environment:

MLflow: 3.16.0
CrewAI: 1.15.18
Python: 3.12.3
opentelemetry-exporter-otlp-proto-http: 1.42.1
1. Direct serialization proof

The following demonstrates the vulnerability without starting a Crew, making a network request, or requiring an MLflow server:

import importlib
from crewai import LLM, Agent

autolog = importlib.import_module("mlflow.crewai.autolog")

llm = LLM(
    model="gpt-4.1-mini",
    api_key="sk-proj-EXAMPLE1234567890",
)

agent = Agent(
    role="r",
    goal="g",
    backstory="b",
    llm=llm,
)

attrs = autolog._get_agent_attributes(agent)

assert "sk-proj-EXAMPLE1234567890" in attrs["llm"]

print(attrs["llm"])

The output contains the API key in plaintext, for example:

llm_type='openai' model='gpt-4.1-mini' ... api_key='sk-proj-EXAMPLE1234567890' ...

No provider request is required.

2. End-to-end trace disclosure

The issue can also be reproduced through MLflow's actual OTLP exporter.

Configure a local OTLP HTTP receiver and set:

export OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=http://127.0.0.1:4318/v1/traces
export OTEL_EXPORTER_OTLP_TRACES_PROTOCOL=http/protobuf
export CREWAI_DISABLE_TELEMETRY=true

Then run:

import mlflow

from crewai import Agent, Crew, LLM, Task

mlflow.crewai.autolog()

llm = LLM(
    model="gpt-4.1-mini",
    api_key="sk-proj-EXAMPLE1234567890",
)

agent = Agent(
    role="Support Responder",
    goal="Answer support questions",
    backstory="A support agent",
    llm=llm,
)

task = Task(
    description="Answer the user's question",
    expected_output="A response",
    agent=agent,
)

crew = Crew(
    agents=[agent],
    tasks=[task],
)

crew.kickoff()

A local OTLP receiver can decode the ExportTraceServiceRequest sent by MLflow.

The provider request is expected to fail because the credential is intentionally fake. This does not affect the vulnerability: the sensitive value is added to the MLflow span when the instrumentation starts, before the provider call succeeds or fails.

In the tested environment, the fake API key appeared in the exported telemetry in 5 locations across 2 spans, including:

Support Responder
  attributes.llm
  attributes.function_calling_llm
  attributes.agent_executor
  attributes.mlflow.spanInputs

Task.execute_sync
  attributes.mlflow.spanInputs

The captured value is produced by MLflow's actual telemetry/export path rather than being manually inserted into a span.

All credentials used in the reproduction are locally generated fake values. No real API credential is required.

Impact

Type: Sensitive Information Disclosure / Credential Disclosure CWE: CWE-532 — Insertion of Sensitive Information into Log File

Any application using mlflow.crewai.autolog() with a CrewAI LLM configured with an API key can unintentionally disclose that credential through MLflow traces.

The credential is written to trace telemetry even though the application does not explicitly log it.

Anyone with access to the MLflow trace storage or configured OTLP destination may therefore obtain the provider credential. Depending on the deployment, this can include MLflow users, observability operators, or third-party telemetry providers.

The leaked credential can then potentially be used against the corresponding LLM provider account, including for unauthorized API usage and associated costs.

The issue is particularly significant because the credential crosses a trust boundary: a provider API key intended for use by the application is automatically copied into observability telemetry where a broader set of users or systems may have access.

The vulnerability does not require the developer to intentionally log the secret. The only relevant prerequisite is enabling the CrewAI autologging integration.

Patches

Fixed in MLflow 3.17.0 by #25845. mlflow.crewai.autolog() now reduces CrewAI LLM objects to their model name and drops credential-like keys before they are written to span attributes or mlflow.spanInputs.

Remediation
  • Upgrade to mlflow>=3.17.0.
  • Upgrading stops new leakage but does not remove credentials already written. Rotate any LLM provider key that a CrewAI LLM object held (for example one passed as LLM(api_key=...)) while mlflow.crewai.autolog() was enabled on MLflow 2.19.0 through 3.16.x.
  • Delete or redact the affected traces in the MLflow tracking backend and in any OTLP destination they were exported to. The key appears in Agent and Crew span attributes and in mlflow.spanInputs.
Workarounds

If you cannot upgrade yet, disable CrewAI autologging with mlflow.crewai.autolog(disable=True).

Catégorie : Exposure of Sensitive Information to an Unauthorized Actor (CWE-200), Cleartext Storage of Sensitive Information (CWE-312), Insertion of Sensitive Information into Log File (CWE-532)

Vecteur CVSS : CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N

  • github.comhttps://github.com/mlflow/mlflow/security/advisories/GHSA-j7qq-vr8c-xvw3
  • github.comhttps://github.com/mlflow/mlflow/pull/25845
  • github.comhttps://github.com/mlflow/mlflow/commit/20927930d27f0072fcfeb7f024f24ad8c5e77c47
  • github.comhttps://github.com/mlflow/mlflow/releases/tag/v3.17.0
  • github.comhttps://github.com/advisories/GHSA-j7qq-vr8c-xvw3
WebguneWebgune

La nube soberana todo en uno, diseñada y alojada en Francia.

DiscordDiscordGitHubGitHub
+33 (0)9 72 23 25 00support@webgune.cloud

Producto

  • Funcionalidades
  • Precios
  • Comparativa
  • Changelog
  • Estado
  • Vulnerabilidades (CVE)
  • Contacto

Desarrolladores

  • Documentación
  • Frameworks
  • Referencia API
  • Ejemplos
  • CLI
  • Herramientas y VS Code

Legal

  • Condiciones de uso
  • Política de privacidad
  • Aviso legal
  • Accesibilidad
  • RGPD
  • DPA
  • Política de uso aceptable

© 2026 KX712. Todos los derechos reservados. Webgune es un servicio de KX712.

Pagos:VisaMasterCardAmerican ExpressApple PayGoogle PaySEPABancontact