Back to skill

Security audit

Metacognition

Security checks for vulnerabilities and agentic risk

Overview

This self-reflection skill is broadly purpose-aligned, but its code contradicts its security claims and can send memory-derived text to an unvalidated embeddings URL while creating persistent agent guidance.

Install only if you are comfortable with a persistent agent-memory tool that reads session or note content and writes future guidance. Before use, fix or disable embeddings unless the URL is strictly loopback, review generated memory entries before loading the lens into an agent, and avoid running the cron integration on transcripts or notes that may contain quoted instructions or sensitive content.

Vulnerability Patterns
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (2)

T09 · Insecure Skill Coding Practices

Error
Location
metacognition.py:42
Finding

Unrestricted Embeddings URL Can Disclose Conversation-Derived Data

Content
View full analysis
bool: """Check if the local embeddings endpoint is reachable.""" global _embeddings_available if _embeddings_available is not None: return _embeddings_available try: result = subprocess.run( ["curl", "-s", "-m", "2", "-X", "POST", EMBEDDINGS_URL, "-H", "Content-Type: application/json", "-d", json.dumps({"input": "test"})], capture_output=True, text=True, timeout=5, ) if result.returncode == 0 and result.stdout.strip(): resp = json.loads(result.stdout) if "data" in resp and resp["data"]: _embeddings_available = True return True except Exception: pass _embeddings_available = False return False def get_embedding(text: str) -> "list": """Get embedding vector from local endpoint. Returns None on failure.""" if not _test_embeddings(): return None try: result = subprocess.run( ["curl", "-s", "-m", "10", "-X", "POST", EMBEDDINGS_URL, "-H", "Content-Type: application/json", "-d", json.dumps({"input": text[:2000]})], # truncate long texts capture_output=True, text=True, timeout=15, ) if result.returncode == 0: resp = json.loads(result.stdout) return resp["data"][0]["embedding"] except Exception: pass return None ``` ### Technical Analysis `EMBEDDINGS_URL` is accepted ...[truncated 2764 chars]
Remediation
View remediation

T02 · Agent Memory Poisoning

Warning
Location
metacognition.py:254
Finding

Untrusted Notes and Session Content Can Poison Persistent Agent Guidance

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (8)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding

The skill advertises executable behavior and access to environment variables, filesystem reads/writes, and shell commands, but it does not declare an explicit tool scope such as permissions or allowed-tools. That mismatch increases the chance that a host agent grants broader capabilities than intended, making the cron/integration instructions capable of reading session history and mutating workspace files without clear least-privilege boundaries.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The skill description suggests local transcript-based self-reflection, but the code transmits memory text to an embeddings service via HTTP. That mismatch is dangerous because operators may grant the skill access to sensitive notes assuming local-only processing, while the implementation can export that content off-process and potentially off-host.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · metacognition.py (reported line 74)May include surrounding context.

python
if _embeddings_available is not None:
        return _embeddings_available
    try:
        result = subprocess.run(
            ["curl", "-s", "-m", "2", "-X", "POST", EMBEDDINGS_URL,
             "-H", "Content-Type: application/json",
             "-d", json.dumps({"input": "test"})],

Tainted flow: 'EMBEDDINGS_URL' from os.environ.get (line 42, credential/environment) → subprocess.run (code execution)

Medium
Category
Data Flow
Confidence
91% confidence
Finding

EMBEDDINGS_URL is taken from the environment and used as the destination of an outbound curl request without validation. An attacker who can influence environment variables can redirect requests to an arbitrary host, causing SSRF-style behavior or exfiltration of local activity metadata and later content sent by the skill.

Content

Scanner excerpt · metacognition.py (reported line 74)May include surrounding context.

python
if _embeddings_available is not None:
        return _embeddings_available
    try:
        result = subprocess.run(
            ["curl", "-s", "-m", "2", "-X", "POST", EMBEDDINGS_URL,
             "-H", "Content-Type: application/json",
             "-d", json.dumps({"input": "test"})],

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · metacognition.py (reported line 96)May include surrounding context.

python
if not _test_embeddings():
        return None
    try:
        result = subprocess.run(
            ["curl", "-s", "-m", "10", "-X", "POST", EMBEDDINGS_URL,
             "-H", "Content-Type: application/json",
             "-d", json.dumps({"input": text[:2000]})],  # truncate long texts

Tainted flow: 'EMBEDDINGS_URL' from os.environ.get (line 42, credential/environment) → subprocess.run (code execution)

Medium
Category
Data Flow
Confidence
96% confidence
Finding

This call sends entry text derived from notes and memory content to whatever URL is in EMBEDDINGS_URL, again without validation. In the context of a self-reflection memory skill, that text may contain sensitive internal prompts, decisions, protections, or user-derived content, so a maliciously set endpoint can silently capture confidential data.

Content

Scanner excerpt · metacognition.py (reported line 96)May include surrounding context.

python
if not _test_embeddings():
        return None
    try:
        result = subprocess.run(
            ["curl", "-s", "-m", "10", "-X", "POST", EMBEDDINGS_URL,
             "-H", "Content-Type: application/json",
             "-d", json.dumps({"input": text[:2000]})],  # truncate long texts

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
81% confidence
Finding

The markdown explains that the skill analyzes session transcripts and compiles self-knowledge, which may involve processing sensitive conversation data. While the Security section discusses localhost embeddings and network limits, it does not explicitly warn users about privacy implications or advise caution when using real transcripts.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

The manifest specifically says patterns are extracted from session transcripts, suggesting a constrained input source. The implementation instead accepts any file path for extraction and, during integration, automatically selects the latest dated markdown note from the memory directory, broadening the actual data sources beyond the described transcript scope.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.