Back to skill

Security audit

hawk-memory-v2

Security checks for vulnerabilities and agentic risk

Overview

This appears to be a real memory tool, but it needs review because it can persist conversations, inject recalled memory as high-priority instructions, and route sensitive content or credentials to external AI providers.

Install only if you are comfortable with a memory layer that persists conversation-derived data locally and may send prompts, recalled memories, markdown memory files, and API credentials to configured AI providers. Use local or keyword modes where possible, avoid storing secrets, review and purge ~/.hawk regularly, and do not use custom LLM endpoints unless you fully trust them.

Vulnerability Patterns
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
Findings (6)

T09 · Insecure Skill Coding Practices

Error
Location
hawk/extractor.py:119
Finding

Cross-provider API credential disclosure

Content
View full analysis
list[ExtractedMemory]: """使用配置的 LLM 从对话中提取记忆""" api_key = api_key or os.environ.get("OPENAI_API_KEY") or os.environ.get("GROQ_API_KEY") or os.environ.get("MINIMAX_API_KEY") or "" ``` ```python # hawk/extractor.py:230-238 req = urllib.request.Request( "https://api.groq.com/openai/v1/chat/completions", data=data, headers={ "Authorization": f"Bearer {api_key or 'free'}", "Content-Type": "application/json", } ) with urllib.request.urlopen(req, timeout=30) as resp: ``` ```python # hawk/wrapper.py:73-81 api_key = api_key or os.environ.get("MINIMAX_API_KEY") or os.environ.get("OPENAI_API_KEY") or "" provider = provider or os.environ.get("LLM_PROVIDER", "keyword") model = model or os.environ.get("OPENAI_MODEL", "llama-3.3-70b-versatile") if base_url is None: if provider == "minimax": base_url = os.environ.get("MINIMAX_BASE_URL", "https://api.minimaxi.com/anthropic") elif provider == "openai": base_url = "https://api.openai.com/v1" ``` ### Technical Analysis Credential selection is not scoped to the selected provider. The extractor searches OpenAI, Groq, and MiniMax environment variables in a fixed order and uses the first available value. The wrapper similarly prefers a MiniMax key even when another provider is selected. The selected value is subsequently placed in a bearer authorization header or supplied to the provider SDK. Consequently, an OpenAI key can be sent to Groq, or a MiniMax key can be sent to OpenAI. This violates credential isolation and least-privilege principles. ### Attack Path 1. ...[truncated 823 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
hawk/wrapper.py:171
Finding

Unfiltered disclosure of conversations and memory files to external AI services

Content
View full analysis
Remediation
View remediation

T02 · Agent Memory Poisoning

Error
Location
hawk/wrapper.py:148
Finding

Persistent prompt injection through system-level recalled memory

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
hawk/extractor.py:306
Finding

Unvalidated custom endpoints can receive credentials and conversation content

Content
View full analysis
list[ExtractedMemory]: """OpenClaw's configured provider (Minimax etc.) — uses OpenAI-compatible endpoint""" try: from openai import OpenAI except ImportError: import urllib.request chat_url = base_url.replace('/anthropic', '') + '/chat/completions' data = json.dumps({ "model": model, "messages": [ {"role": "system", "content": "你是一个精确的记忆提取引擎。只输出JSON数组,不输出任何其他内容。"}, {"role": "user", "content": prompt} ], "temperature": 0.1, "max_tokens": 2000, }).encode() req = urllib.request.Request( chat_url, data=data, headers={ "Authorization": f"Bearer {api_key}", "Content-Type": "application/json", } ) ``` ```python # hawk/extractor.py:336-340 chat_base = base_url.replace('/anthropic', '') client = OpenAI(api_key=api_key, base_url=chat_base) response = client.chat.completions.create( model=model, messages=[ ``` ```python # hawk/extractor.py:390 parser.add_argument("--base-url", default=os.environ.get("LLM_BASE_URL", "") or os.environ.get("MINIMAX_BASE_URL", "")) ``` ```python # hawk/wrapper.py:78-89 if base_url is None: if provider == "minimax": base_url = os.environ.get("MINIMAX_BASE_URL", "https://api.minimaxi.com/anthropic") elif provider == "openai": base_url = "https://api.openai.com/v1" elif provider == "ollama": base_url = os.environ.get("OLLAMA_BASE_URL", "http://localhost:11434") else: base_url = "" self.cfg = HawkConfig( ...[truncated 1560 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
hawk/config.py:41
Finding

Environment-derived API key can be saved in plaintext

Content
View full analysis
Remediation
View remediation

T08 · Insecure Dependencies

Note
Location
scripts/install.sh:11
Finding

Installer retrieves unpinned third-party dependencies

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (93)

Tainted flow: 'req' from os.environ.get (line 323, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · hawk/extractor.py (reported line 238)May include surrounding context.

python
"Content-Type": "application/json",
            }
        )
        with urllib.request.urlopen(req, timeout=30) as resp:
            result = json.loads(resp.read())
            content = result["choices"][0]["message"]["content"]
            return parse_and_validate(content)

Tainted flow: 'req' from os.environ.get (line 230, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · hawk/extractor.py (reported line 272)May include surrounding context.

python
data=data,
        headers={"Content-Type": "application/json"}
    )
    with urllib.request.urlopen(req, timeout=60) as resp:
        result = json.loads(resp.read())
        content = result["message"]["content"]
        return parse_and_validate(content)

Tainted flow: 'req' from os.environ.get (line 230, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · hawk/extractor.py (reported line 300)May include surrounding context.

python
"X-Title": "hawk-bridge",
        }
    )
    with urllib.request.urlopen(req, timeout=30) as resp:
        result = json.loads(resp.read())
        content = result["choices"][0]["message"]["content"]
        return parse_and_validate(content)

Tainted flow: 'req' from os.environ.get (line 323, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

extract_with_openclaw constructs the destination URL from base_url, which is ultimately sourced from LLM_BASE_URL/MINIMAX_BASE_URL or CLI input, then sends full conversation content and credentials to that computed endpoint. If an attacker can influence configuration, this enables server-side data exfiltration to an arbitrary host and effectively turns the component into a configurable outbound proxy for sensitive conversation data.

Content

Scanner excerpt · hawk/extractor.py (reported line 331)May include surrounding context.

python
"Content-Type": "application/json",
            }
        )
        with urllib.request.urlopen(req, timeout=30) as resp:
            result = json.loads(resp.read())
            content = result["choices"][0]["message"]["content"]
            return parse_and_validate(content)

Intent-Code Divergence

High
Category
Not specified by scanner
Confidence
94% confidence
Finding

The module and method documentation describe this as an 'incremental import' using hawk:imported tags for deduplication, but embed_and_store drops the entire LanceDB table whenever it exists before recreating it. That behavior is destructive replacement, not incremental import, and directly contradicts the stated intent in the docstring/comments.

Content

No source excerpt is available for this finding.

Missing User Warnings

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

User markdown content is transmitted to the OpenAI embeddings API without any user-facing warning, consent, or confirmation step. In a memory-import context, that makes the risk more serious because the source directory is explicitly intended to hold user memory and may contain highly sensitive information the user did not expect to be sent to a third party.

Content

No source excerpt is available for this finding.

Missing User Warnings

High
Category
Not specified by scanner
Confidence
95% confidence
Finding

chat() sends accumulated messages to external LLM providers via _call_llm(), but the wrapper does not provide any user-facing disclosure that prompts and recalled content may leave the local environment. Because this wrapper also injects recalled memories and maintains conversation history, more data than the immediate user prompt may be transmitted, increasing confidentiality risk.

Content

No source excerpt is available for this finding.

Missing User Warnings

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

On context exit, exit automatically calls capture(), which extracts and stores recent conversation content to local memory without any explicit consent, notice, or opt-in. In an LLM wrapper, conversations frequently contain secrets, personal data, credentials, or proprietary content, so silent persistence materially increases privacy and retention risk.

Content

No source excerpt is available for this finding.

Self-Modification

High
Category
Rogue Agent
Confidence
85% confidence
Finding

Skill modifies its own code, configuration, or behavior at runtime. Self-modification enables an agent to escalate privileges, disable safety constraints, or install persistent backdoors.

Content

Scanner excerpt · references/task-state.md (reported line 32)May include surrounding context.

md
"steps": [
    {
      "id": 1,
      "description": "Write SKILL.md",
      "status": "completed",
      "done_at": "2026-03-29T00:15:00+08:00"
    },

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The README prominently promotes persistent cross-session memory, including task status and user preferences, but does not clearly warn users that conversation-derived data may be stored durably in local JSONL files and reused after restart. This creates a privacy and consent risk: operators may enable the skill without realizing it retains potentially sensitive session content beyond the current interaction.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The automatic trigger section describes periodic context review, importance scoring, and compression actions, but does not clearly explain the consequences for stored user data, including automatic processing, summarization, archival, or deletion of previously captured content. That omission can mislead users about how their data is transformed over time and increases the chance that sensitive information is retained or reprocessed without informed consent.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

El README promueve persistencia automática entre sesiones y almacenamiento local de memoria/preferencias, pero no incluye una advertencia clara sobre retención de datos, sensibilidad del contenido ni necesidad de consentimiento del usuario. En una skill de memoria contextual, esto aumenta el riesgo de recopilar y conservar información personal o sensible más allá de lo que el usuario espera.

Content

No source excerpt is available for this finding.

Ssd 3

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

La documentación describe reanudar tareas entre sesiones mediante almacenamiento persistente de estado y salidas, lo que crea una instrucción semántica para retener y volver a exponer datos proporcionados por el usuario. Si el estado de tarea o los outputs contienen secretos, datos personales o información confidencial, estos podrían permanecer en disco y ser recuperados posteriormente sin controles adicionales.

Content

No source excerpt is available for this finding.

Ssd 3

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

El esquema de memoria indica conservar el "contenido original completo", una formulación demasiado amplia para una función de memoria automática. En el contexto de una skill cuyo propósito es recordar conversaciones y preferencias, esto hace más probable la captura indiscriminada de información sensible del usuario y su posterior reexposición en futuras respuestas.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The README explicitly promotes silent application of user preferences across sessions and describes automatic persistence of task state and memories to local JSONL files, but it does not clearly warn users about privacy, retention, or consent implications. In a memory-management skill, this increases the risk of storing sensitive personal, conversational, or task data without informed user awareness, especially when persistence happens by default.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

Il README promuove una memoria persistente tra sessioni ma non avvisa in modo chiaro, anticipato ed esplicito che contenuti conversazionali, preferenze e stato attività possono essere salvati su disco locale. Questo può portare utenti o operatori ad attivare la skill senza comprendere che dati potenzialmente sensibili verranno conservati oltre la sessione corrente, aumentando il rischio di esposizione locale, raccolta eccessiva o retention non intenzionale.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

La sezione sulla ripresa automatica enfatizza che la skill 'riprende esattamente da dove aveva lasciato' e mostra esempi di stato attività persistito, ma non accompagna questa capacità con un warning esplicito sulla permanenza dei dati dopo riavvii o cambi di sessione. In un contesto di agente IA, ciò è più pericoloso perché task state, output, vincoli e passaggi successivi possono contenere informazioni operative o sensibili che l'utente potrebbe presumere effimere.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

La sezione sulla memoria strutturata indica esplicitamente che possono essere memorizzati content completo, preferenze, conversazioni, conoscenza e decisioni, ma non avverte chiaramente che tali dati possono diventare memoria persistente. Questo è particolarmente rischioso perché il contenuto completo delle conversazioni può includere credenziali, dati personali, informazioni aziendali o istruzioni sensibili, creando un rischio concreto di leakage locale e conservazione non conforme alle aspettative dell'utente.

Content

No source excerpt is available for this finding.

Ae4

Medium
Category
analysis-evasion
Confidence
80% confidence
Finding

Suspicious Unicode normalization or mixed-script content

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The skill explicitly promotes cross-session memory and persistent storage, but the description does not clearly warn users that conversation data, preferences, and task state may be retained on disk over time. This creates a privacy and data-retention risk because users may disclose sensitive information assuming normal ephemeral agent behavior, while the skill persists it locally.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The examples show concrete on-disk paths and persisted task contents, including task descriptions, outputs, and constraints, without an explicit warning that real user/task data will be written to local files. In a memory-management skill, this context increases the danger because the entire purpose is to capture and retain agent context, which may include sensitive business, personal, or credential-adjacent information.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The README prominently advertises cross-session automatic memory capture and persistence, but it does not clearly warn that user conversations, preferences, and task details may be retained on disk. In an AI-agent context, users may disclose sensitive operational, personal, or proprietary information to the agent, so silent persistence materially increases privacy and data-handling risk.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The examples show concrete local JSONL persistence of task state, outputs, constraints, and resumable work state, yet the documentation does not clearly warn that sensitive work artifacts may be written to disk in plaintext. This creates a realistic risk of confidential data exposure through local file access, backups, sync tools, or accidental sharing of the working directory.

Content

No source excerpt is available for this finding.

Ssd 3

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The structured memory example explicitly includes complete original content and preference/conversation categories for storage across sessions, which creates a built-in natural-language retention surface. In a memory skill, that means prompts, user preferences, internal project details, and possibly secrets can accumulate and later be retrieved, increasing the chance of unintended disclosure or over-retention.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The README explicitly promotes cross-session memory retention and says the agent can silently apply user preferences from prior sessions, but it does not clearly disclose privacy, consent, retention, or review/deletion controls at the point of introduction. In a memory skill, this can lead users to unknowingly persist sensitive personal preferences or conversation details, increasing the risk of unauthorized retention and surprise data use.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.