GHSA-j7qq-vr8c-xvw3: Infoleak

Published Oct 27, 2026
·
Updated

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 apikey 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::getagentattributes()

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 functioncallingllm agentexecutor crew

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

text llmtype='openai' model='gpt-4.1-mini' ... apikey='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 apikey in getllmattributes(). 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::constructfullinputs()

This code uses:

python 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 getagentattributes() 2. Span inputs through constructfullinputs()

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, functioncallingllm, agentexecutor, and crew should either be reduced to safe metadata or omitted.

Similarly, constructfullinputs() 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:

text 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:

python import importlib from crewai import LLM, Agent

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

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

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

attrs = autolog.getagentattributes(agent)

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

print(attrs["llm"])

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

text llmtype='openai' model='gpt-4.1-mini' ... apikey='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:

bash export OTELEXPORTEROTLPTRACESENDPOINT=http://127.0.0.1:4318/v1/traces export OTELEXPORTEROTLPTRACESPROTOCOL=http/protobuf export CREWAIDISABLETELEMETRY=true

Then run:

python import mlflow

from crewai import Agent, Crew, LLM, Task

mlflow.crewai.autolog()

llm = LLM( model="gpt-4.1-mini", apikey="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", expectedoutput="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:

text Support Responder attributes.llm attributes.functioncallingllm attributes.agentexecutor attributes.mlflow.spanInputs

Task.executesync 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(apikey=...)) 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).

Affected Software

1 affected componentFixes available
pip/mlflow>=2.19.0<3.17.0
3.17.0

Remediation

Recommended actions to resolve this vulnerability, in priority order.

  1. Upgrade

    Upgrade pip/mlflow to a version that resolves this vulnerability.

    Fixed in 3.17.0
  2. Upgrade

    Upgrade MLflow to a version that resolves this vulnerability.

    Fixed in 3.17.0Patch #25845
  3. Configuration

    Disable CrewAI autologging until MLflow is upgraded.

    CrewAI autologging mlflow.crewai.autolog(disable=True) = disabled
  4. Operational

    Delete or redact affected traces in the MLflow tracking backend and in any OTLP destination to which they were exported.

  5. Operational

    Rotate any LLM provider key that a CrewAI LLM object held while mlflow.crewai.autolog() was enabled on MLflow 2.19.0 through 3.16.x.

Event History

Oct 27, 2026
Advisory Published
via GitHub·09:26 PM
Data Sourced
via GitHub·09:26 PM
DescriptionSeverityWeaknessAffected Software

Frequently Asked Questions

1

Who is exposed to this issue?

Applications using MLflow's CrewAI autologging with CrewAI agents are exposed when an agent contains an LLM provider API key in a credential-bearing object such as its llm field. The issue was verified with MLflow 3.16.0 and CrewAI 1.15.18.

2

What does an attacker need to exploit this?

No explicit credential logging or span attribute is required. Calling mlflow.crewai.autolog() causes MLflow instrumentation to serialize agent fields, which can place the API key in trace telemetry sent to the MLflow trace backend or a configured OTLP destination.

3

How can I determine whether credentials were already exposed?

Inspect MLflow trace telemetry and any configured OTLP destination for CrewAI agent traces and their attributes. In the verified scenario, the credential appeared in five attribute locations across two spans.

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203