Lethe

Security checks across malware telemetry and agentic risk

Overview

This is a real persistent-memory plugin, but it stores and reuses broad conversation content with weak scoping and no visible redaction, so users should review it before installing.

Install only if you are comfortable with an agent memory layer storing and later replaying conversation-derived content. Use a trusted local Lethe endpoint unless you intentionally want remote storage, avoid sharing secrets while it is enabled, and verify retention, deletion, redaction, and session-scoping behavior before using it for private or regulated work.

SkillSpector

By NVIDIA
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Memory PoisoningPersistent Context Injection, Context Window Stuffing, Memory Manipulation
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (29)

Intent-Code Divergence

Low
Confidence
88% confidence
Finding
The bootstrap comment explicitly documents creation via POST /sessions in the context of other /api/sessions endpoints, but the implementation later creates the session at a different path than the surrounding documented API shape. This is an intent/documentation mismatch because the inline documentation describes one behavior/interface while the code performs another.

Intent-Code Divergence

Medium
Confidence
87% confidence
Finding
The comments at L182-L183 state that the hard cap on recent events is the primary guard against '/new' overflow. However, in assemble(), the summary is always fetched and prepended when present (L192-L205, L249-L254), with no equivalent cap or truncation for summary size. This documentation overstates the protection actually implemented and could mislead maintainers about context-growth behavior.

Intent-Code Divergence

Medium
Confidence
95% confidence
Finding
The surrounding comment and tool description present this as a memory search tool that can be session-scoped via sessionKey, but the implementation always performs a global cross-session search first and only falls back to session scope when no global results are found. This is an intent-level contradiction because a caller providing sessionKey would reasonably expect the search to honor that scope rather than ignore it initially.

Intent-Code Divergence

Medium
Confidence
91% confidence
Finding
The tool description frames the capability as searching past decisions and context, while the parameter schema at L077 describes sessionKey as an override for session-scoped search. In code, the tool always queries the global /events/search endpoint first and only falls back to a session-specific search if no global results are found, which contradicts the documented session-scoping behavior.

Ssd 3

High
Confidence
94% confidence
Finding
The code converts full conversation messages into log content and stores them as session events, including raw user text and assistant text. This natural-language behavior amounts to retaining and transmitting everything the user says to an external service, which creates a data-leak risk even though it is framed as routine memory ingestion rather than explicit exfiltration.

Ssd 3

High
Confidence
88% confidence
Finding
The code takes prior session summaries and recent memory events from external storage and reintroduces them into the prompt as trusted context. If those memories contain credentials, personal data, or confidential user content, the model is being instructed to carry forward and reuse that information in future responses, which is a natural-language data exposure pattern.

Ssd 3

Medium
Confidence
90% confidence
Finding
The ingest path converts every non-heartbeat message into log content and stores it as a session event, including raw user text and assistant text. This creates a natural-language data retention and resurfacing mechanism: anything a user shares may be remembered, summarized, and reintroduced into later context without clear narrowing or redaction.

Ssd 3

High
Confidence
87% confidence
Finding
Previous-session summaries and recent memory events are turned into prompt/context material and prepended to future conversations. Because those summaries and events are built from prior message content, the code semantically instructs the system to remember and reuse potentially sensitive user-provided information across sessions, increasing risk of unintended disclosure.

Ssd 3

Medium
Confidence
88% confidence
Finding
The skill frames long-term memory very broadly: decisions, observations, tasks, flags, and historical context are all persisted and later retrieved for future responses. Although presented as helpful memory behavior, this is a plain-language instruction to retain and reuse user-provided information across sessions, which can expose prior sensitive content when answering later prompts.

Ssd 3

Medium
Confidence
84% confidence
Finding
These steps require the agent, on every new session, to retrieve a session summary, recent events, and all unresolved flags before interacting with the user. Semantically, this is a directive to collect and process potentially sensitive historical content by default, even when the current request may not require it, which raises data-leak and over-collection concerns.

Ssd 3

Medium
Confidence
80% confidence
Finding
The recording section tells the agent to log decisions, observations, flags, and tasks into durable memory, but the exclusions focus on usefulness rather than sensitivity. In practice, this natural-language guidance can cause the agent to retain private or confidential information shared during normal conversation and later reproduce it.

External Transmission

Medium
Category
Data Exfiltration
Content
--arg tid "$TASK_ID" \
      --arg stat "$STATUS" \
      '{task_status: $stat}')
    RESULT=$(curl -s -X PUT "$API/api/sessions/$SESSION_ID/events/$TASK_ID" \
      -H "Content-Type: application/json" \
      -d "$PAYLOAD")
    echo "Task updated: $RESULT"
Confidence
60% confidence
Finding
curl -s -X PUT "$API/api/sessions/$SESSION_ID/events/$TASK_ID" \ -H "Content-Type: application/json" \ -d

External Transmission

Medium
Category
Data Exfiltration
Content
--arg conf "$CONFIDENCE" \
      --arg tags "${TAGS:-[]}" \
      '{event_type: "task", content: $content, confidence: ($conf | tonumber), tags: ($tags | split(",") | map(select(length > 0))), task_title: $content, task_status: $stat}')
    RESULT=$(curl -s -X POST "$API/api/sessions/$SESSION_ID/events" \
      -H "Content-Type: application/json" \
      -d "$PAYLOAD")
    echo "Task created: $(echo $RESULT | jq -r '.event_id // .event_id')"
Confidence
60% confidence
Finding
curl -s -X POST "$API/api/sessions/$SESSION_ID/events" \ -H "Content-Type: application/json" \ -d

External Transmission

Medium
Category
Data Exfiltration
Content
--arg tags "${TAGS:-[]}" \
    '{event_type: $type, content: $content, confidence: ($conf | tonumber), tags: ($tags | split(",") | map(select(length > 0)))}')
  
  RESULT=$(curl -s -X POST "$API/api/sessions/$SESSION_ID/events" \
    -H "Content-Type: application/json" \
    -d "$PAYLOAD")
Confidence
60% confidence
Finding
curl -s -X POST "$API/api/sessions/$SESSION_ID/events" \ -H "Content-Type: application/json" \ -d

External Transmission

Medium
Category
Data Exfiltration
Content
--arg tid "$TASK_ID" \
      --arg stat "$STATUS" \
      '{task_status: $stat}')
    RESULT=$(curl -s -X PUT "$API/api/sessions/$SESSION_ID/events/$TASK_ID" \
      -H "Content-Type: application/json" \
      -d "$PAYLOAD")
    echo "Task updated: $RESULT"
Confidence
60% confidence
Finding
curl -s -X PUT "$API/api/sessions/$SESSION_ID/events/$TASK_ID" \ -H "Content-Type: application/json" \ -d

External Transmission

Medium
Category
Data Exfiltration
Content
--arg conf "$CONFIDENCE" \
      --arg tags "${TAGS:-[]}" \
      '{event_type: "task", content: $content, confidence: ($conf | tonumber), tags: ($tags | split(",") | map(select(length > 0))), task_title: $content, task_status: $stat}')
    RESULT=$(curl -s -X POST "$API/api/sessions/$SESSION_ID/events" \
      -H "Content-Type: application/json" \
      -d "$PAYLOAD")
    echo "Task created: $(echo $RESULT | jq -r '.event_id // .event_id')"
Confidence
60% confidence
Finding
curl -s -X POST "$API/api/sessions/$SESSION_ID/events" \ -H "Content-Type: application/json" \ -d

External Transmission

Medium
Category
Data Exfiltration
Content
--arg tags "${TAGS:-[]}" \
    '{event_type: $type, content: $content, confidence: ($conf | tonumber), tags: ($tags | split(",") | map(select(length > 0)))}')
  
  RESULT=$(curl -s -X POST "$API/api/sessions/$SESSION_ID/events" \
    -H "Content-Type: application/json" \
    -d "$PAYLOAD")
Confidence
60% confidence
Finding
curl -s -X POST "$API/api/sessions/$SESSION_ID/events" \ -H "Content-Type: application/json" \ -d

Scope Creep

Low
Category
Excessive Agency
Content
- Events are append-only. Nothing is ever deleted unless you explicitly delete it.
- Compaction synthesizes events into a narrative summary — it does not delete history.
- Memory search retrieves facts. Recording captures decisions. Flags surface uncertainty.
- The plugin fires on `bootstrap()` and `assemble()` — you handle everything else.

---
Confidence
70% confidence
Finding
handle everything

Memory Manipulation

High
Category
Memory Poisoning
Content
**Mental model:**
- Events are append-only. Nothing is ever deleted unless you explicitly delete it.
- Compaction synthesizes events into a narrative summary — it does not delete history.
- Memory search retrieves facts. Recording captures decisions. Flags surface uncertainty.
- The plugin fires on `bootstrap()` and `assemble()` — you handle everything else.
Confidence
80% confidence
Finding
delete history

Unpinned Dependencies

Low
Category
Supply Chain
Content
},
  "peerDependencies": {
    "@mariozechner/pi-agent-core": "^0.70.0",
    "openclaw": "*"
  },
  "devDependencies": {
    "@mariozechner/pi-agent-core": "^0.70.0",
Confidence
70% confidence
Finding
"openclaw": "*"

Unpinned Dependencies

Low
Category
Supply Chain
Content
"devDependencies": {
    "@mariozechner/pi-agent-core": "^0.70.0",
    "@types/node": "^20.0.0",
    "openclaw": "*",
    "typescript": "^5.4.0",
    "tsc-alias": "^1.8.0"
  }
Confidence
70% confidence
Finding
"openclaw": "*"

Unpinned Dependencies

Low
Category
Supply Chain
Content
"clean": "rm -rf dist"
  },
  "dependencies": {
    "@sinclair/typebox": "^0.34.0"
  },
  "peerDependencies": {
    "@mariozechner/pi-agent-core": "^0.70.0",
Confidence
40% confidence
Finding
"@sinclair/typebox": "^0.34.0"

Unpinned Dependencies

Low
Category
Supply Chain
Content
"@sinclair/typebox": "^0.34.0"
  },
  "peerDependencies": {
    "@mariozechner/pi-agent-core": "^0.70.0",
    "openclaw": "*"
  },
  "devDependencies": {
Confidence
40% confidence
Finding
"@mariozechner/pi-agent-core": "^0.70.0"

Unpinned Dependencies

Low
Category
Supply Chain
Content
"openclaw": "*"
  },
  "devDependencies": {
    "@mariozechner/pi-agent-core": "^0.70.0",
    "@types/node": "^20.0.0",
    "openclaw": "*",
    "typescript": "^5.4.0",
Confidence
40% confidence
Finding
"@mariozechner/pi-agent-core": "^0.70.0"

Unpinned Dependencies

Low
Category
Supply Chain
Content
},
  "devDependencies": {
    "@mariozechner/pi-agent-core": "^0.70.0",
    "@types/node": "^20.0.0",
    "openclaw": "*",
    "typescript": "^5.4.0",
    "tsc-alias": "^1.8.0"
Confidence
40% confidence
Finding
"@types/node": "^20.0.0"

VirusTotal

63/63 vendors flagged this plugin as clean.

View on VirusTotal