
# Detaillierte Analyse von CVE-2026-22038 Detaillierte Analyse von CVE-2026-22038, einer Schwachstelle mit hohem Schweregrad in AutoGPT-Stagehand-Blöcken, die API-Schlüssel im Klartext protokolliert, einschließlich Ursache, Auswirkungen und Abhilfemaßnahmen.
CVE-ID: CVE-2026-22038
Produkt: AutoGPT-Plattform (Stagehand-Integration)
Betroffene Versionen: Alle Versionen bis einschließlich autogpt-platform-beta-v0.6.45
Behoben in: autogpt-platform-beta-v0.6.46
Schwachstellentyp: CWE-532 — Einfügung vertraulicher Informationen in Protokolldateien
Schweregrad: Hoch
Gemeldet von: Panuganti Siva Aditya (@sivaadityacoder)
Meldedatum: 19. Dezember 2025
GitHub Advisory: GHSA-rc89-6g7g-v5v7
AutoGPT ist eine Open-Source-Plattform, mit der Benutzer autonome KI-Agenten erstellen und ausführen können. Sie enthält eine Stagehand-Integration, die eine Verbindung zu Browser-Automatisierung und LLM-Anbietern wie OpenAI, Anthropic und Groq herstellt.
Bei einer Code-Überprüfung der Stagehand-Blöcke fiel mir auf, dass Anmeldedaten-Objekte direkt an logger.info()-Aufrufe übergeben wurden. Ich verfolgte jede Protokollanweisung und stellte fest, dass inline aufgerufen wurde — wodurch der von Pydantic bereitgestellte -Schutz explizit umgangen wurde.
.get_secret_value()SecretStrDie verwundbare Datei:
autogpt_platform/backend/backend/blocks/stagehand/blocks.py
Drei Blöcke sind betroffen, jeweils mit demselben Muster:
StagehandObserveBlock (Zeilen 185–188)
logger.info(f"OBSERVE: Stagehand credentials: {stagehand_credentials}")
logger.info(
f"OBSERVE: Model credentials: {model_credentials} for provider "
f"{model_credentials.provider} secret: {model_credentials.api_key.get_secret_value()}"
)
StagehandActBlock (Zeilen 285–288)
logger.info(f"ACT: Stagehand credentials: {stagehand_credentials}")
logger.info(
f"ACT: Model credentials: {model_credentials} for provider "
f"{model_credentials.provider} secret: {model_credentials.api_key.get_secret_value()}"
)
StagehandExtractBlock (Zeilen 373–376)
logger.info(f"EXTRACT: Stagehand credentials: {stagehand_credentials}")
logger.info(
f"EXTRACT: Model credentials: {model_credentials} for provider "
f"{model_credentials.provider} secret: {model_credentials.api_key.get_secret_value()}"
)
Um die Ausnutzbarkeit zu bestätigen, führte ich jeden Stagehand-Block mit gültigen Anmeldedaten aus und durchsuchte die Anwendungsprotokolle:
grep "secret:" /var/log/autogpt/application.log
Die Ausgabe bestätigte, dass echte API-Schlüssel im Klartext erschienen:
[INFO] OBSERVE: Model credentials: ... secret: sk-proj-abc123xyz789...
[INFO] ACT: Model credentials: ... secret: sk-ant-api03-def456uvw...
[INFO] EXTRACT: Model credentials: ... secret: sk-1234567890abcdef...
Die AutoGPT-Codebasis verwendet korrekt den SecretStr-Typ von Pydantic für API-Schlüssel. Wenn ein SecretStr-Objekt in einen f-String eingefügt oder normal ausgegeben wird, wird es als ********** dargestellt — dieser Schutz ist beabsichtigt.
Die Grundursache ist, dass die Entwickler .get_secret_value() direkt innerhalb der logger.info()-Anweisungen aufgerufen haben. Dadurch wird das Geheimnis explizit entschlüsselt und der rohe Zeichenfolgenwert an den Logger übergeben, wodurch die integrierte Maskierung von SecretStr vollständig umgangen wird.
Die Protokollebene ist INFO, was bedeutet, dass diese Anweisungen in normalen Produktionsumgebungen ausgeführt werden — nicht nur in lokalen Debugging-Sitzungen. Jedes Mal, wenn einer dieser Blöcke mit Anmeldedaten ausgeführt wird, wird das Geheimnis in die Protokolldatei geschrieben.
Angriffsszenario:
secret:, sk-proj- oder sk-ant-.curl https://api.openai.com/v1/chat/completions \
-H "Authorization: Bearer sk-proj-abc123xyz789..." \
-H "Content-Type: application/json" \
-d '{"model": "gpt-4", "messages": [{"role": "user", "content": "test"}]}'
Offengelegte Anmeldedaten: Stagehand-/Browserbase-API-Schlüssel, OpenAI-API-Schlüssel, Anthropic-API-Schlüssel, Groq-API-Schlüssel und alle LLM-Anbieter-Anmeldedaten, die in den Stagehand-Blöcken konfiguriert sind.
Der Patch in autogpt-platform-beta-v0.6.46 entfernt die .get_secret_value()-Aufrufe aus den logger.info()-Anweisungen.
Empfohlener Ansatz — das Geheimnis vollständig aus dem Protokoll entfernen:
# Vorher (verwundbar):
logger.info(
f"OBSERVE: Model credentials: {model_credentials} for provider "
f"{model_credentials.provider} secret: {model_credentials.api_key.get_secret_value()}"
)
# Nachher (behoben):
logger.info(
f"OBSERVE: Model credentials for provider {model_credentials.provider} (API key redacted)"
)
Alternative — Schwärzung unter Beibehaltung der Protokollstruktur:
def redact_secret(value: str) -> str:
if len(value) <= 8:
return "***"
return f"{value[:4]}...{value[-4:]}"
logger.info(
f"OBSERVE: Model credentials for provider {model_credentials.provider} "
f"secret: {redact_secret(model_credentials.api_key.get_secret_value())}"
)
Der Schwärzungsansatz legt nur die ersten und letzten 4 Zeichen offen — genug, um zu identifizieren, welcher Schlüssel verwendet wurde, ohne das vollständige Geheimnis preiszugeben.
Rufen Sie .get_secret_value() niemals in Protokollanweisungen auf. Wenn Ihr Framework einen Typ zur Geheimnismaskierung bereitstellt (SecretStr, SecretBytes usw.), lassen Sie ihn seine Aufgabe erfüllen. Das Aufrufen der Entpackungsmethode innerhalb eines Loggers macht den gesamten Zweck zunichte.
INFO ist Protokollierung auf Produktionsebene. Debug-artige Ausgaben von Anmeldedaten sollten niemals die INFO-Ebene erreichen. Wenn Sie wirklich bestätigen müssen, welche Anmeldedaten aktiv sind, protokollieren Sie nur nicht sensible Metadaten (Anbietername, Schlüsselpräfix, letzte 4 Zeichen).
Protokolldateien sind eine Angriffsfläche. Behandeln Sie sie wie jeden anderen sensiblen Datenspeicher — beschränken Sie den Zugriff, rotieren Sie sie und prüfen Sie, was hineingelangt. Aggregationstools (Splunk, ELK, Datadog) haben oft breiten Lesezugriff, sodass ein Geheimnis in einer Protokollzeile effektiv auch ein Geheimnis in diesen Systemen ist.
Die Behebung ist immer einfacher als der Fehler. Das Entfernen von zwei Protokollzeilen (oder deren Ersetzung durch geschwärzte Äquivalente) schließt diese Offenlegung vollständig. Sicherheitsschulden durch „temporäres Debug-Logging", das in der Produktion verbleibt, sind häufig und durch Code-Überprüfung vermeidbar.
SecretStr-Schutz ist optional, nicht automatisch. Entwickler müssen verstehen, dass der Schutz nur so lange gilt, wie niemand den Wert explizit entpackt. Die Code-Überprüfung sollte jede Verwendung von .get_secret_value() außerhalb des Authentifizierungspfads kennzeichnen.
| Datum | Ereignis |
|---|---|
| 19. Dezember 2025 | Gemeldet an die AutoGPT-Maintainer über Huntr und GitHub Security Advisory |
| 2025–2026 | Maintainer Nicholas Tindle bestätigte den Bericht |
| Vor April 2026 | Behoben in autogpt-platform-beta-v0.6.46 |
| 25. April 2026 | CVE-2026-22038 zugewiesen |