KEVWire

Security intelligence, with context.

Response snapshot Oct 27, 2026, 23:56 UTC

Back to the wire
Permalink
VulnerabilityCVE-2026-116691

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

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.

At a glance

Exploited
Not known
Severity
6.5 Medium (CVSS 3.1)
Chance of exploitation
Not estimated
Sources
1 source

What to do

GitHub lists first patched versions: mlflow: 3.17.0. Confirm the affected range and upgrade guidance in the exact advisory.

Read GitHub-reviewed advisory GHSA-j7qq-vr8c-xvw3 (opens a new tab)

What happened

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.

Continue reading

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

Affected package ranges reported by GitHub: mlflow: >= 2.19.0, < 3.17.0

Scores and how they were measured

CVSS base severity

6.5

Version 3.1As of

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

Measurement source (opens a new tab)

How bad it is if exploited. Not a prediction of exploitation or proof you are exposed.

EPSS probability

Not available

A model's estimate of exploitation in the next 30 days, not certainty or your own risk.

Related technology

Sources

  1. Primary source

    GitHub-reviewed advisory GHSA-j7qq-vr8c-xvw3 (opens a new tab)

    The public advisory supplies the description, affected package/version ranges, and any listed CVSS metric. GitHub review is not local review.

    Published Checked

  2. Primary source

    GitHub public advisory API page (opens a new tab)

    The API page supplied GHSA-j7qq-vr8c-xvw3, its actual identifiers, source dates, and structured metrics.

    Published Date not suppliedChecked

Cite this record

For factual claims, cite the primary sources above; cite KEVWire for its compilation, dates, and classifications.

APA

KEVWire. (2026, October 27). MLflow CrewAI autologging records LLM provider API keys in logged trace spans (CVE-2026-116691). https://kevwire.com/record/CVE-2026-116691

MLA

"MLflow CrewAI autologging records LLM provider API keys in logged trace spans (CVE-2026-116691)." KEVWire, 27 Oct. 2026, kevwire.com/record/CVE-2026-116691.

Chicago

KEVWire. "MLflow CrewAI autologging records LLM provider API keys in logged trace spans (CVE-2026-116691)." Last modified October 27, 2026. https://kevwire.com/record/CVE-2026-116691.

Evidence summary (plain text)

MLflow CrewAI autologging records LLM provider API keys in logged trace spans (Oct 27, 2026).
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.
CVSS 6.5 (version 3.1; evidence as of Oct 27, 2026; https://github.com/advisories/GHSA-j7qq-vr8c-xvw3).
Sources:
GitHub-reviewed advisory GHSA-j7qq-vr8c-xvw3: https://github.com/advisories/GHSA-j7qq-vr8c-xvw3
GitHub public advisory API page: https://api.github.com/advisories?type=reviewed&per_page=100&sort=updated&direction=desc
Record ID: CVE-2026-116691.
Record origin: Ingested record.
AI evidence: Not assessed.
Known exploitation: Not assessed.
Zero-day status: Not assessed. KEV membership alone does not establish zero-day status.
About this data

This record was ingested from a data source. Retrieved: Oct 27, 2026, 23:40 UTC. Ingestion is not an independent editorial investigation.

A CISA KEV listing documents known exploitation, not necessarily a zero-day; absence from the catalog does not prove a vulnerability has never been exploited.

Technology tags indicate possible relevance, not verified exposure. Confirm the affected product, version, and configuration against your own inventory; KEVWire does not scan your systems.

A personal reading checklist on this device, not verified remediation.

Record JSON

Your account

Email alerts

Email alerts are not available yet. To follow your stack today, use its RSS feed, which honors your filters, or connect an AI agent through the API.

Suggest an improvement

Ideas, missing sources, corrections, and bugs are all welcome. No account needed. Suggestions are reviewed by a person before anything changes.

Record details

Record detail