Back to skill

Security audit

Voice Memory Features

Security checks for vulnerabilities and agentic risk

Overview

This skill is a coherent BlueColumn voice-memory integration, but it persistently uploads and recalls broad voice, meeting, journal, CRM, coaching, and sales data with weak scoping and unsafe prompt-injection guidance.

Review this before installing in any real voice, meeting, CRM, sales, or coaching workflow. Only use it where all participants and administrators understand that transcripts and notes may be sent to BlueColumn and made searchable later. Require explicit opt-in, narrow what gets stored, avoid full transcripts where summaries are enough, add redaction and deletion/retention controls, do not place recalled memory in a system prompt, and lock BLUECOLUMN_BASE to a trusted HTTPS endpoint with a narrowly scoped API key.

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 (3)

T09 · Insecure Skill Coding Practices

Error
Location
features/voice_memory.py:17
Finding
Configurable API Endpoint Can Expose Bearer Credentials and Sensitive Voice Data<![CDATA[ ## Vulnerability Details **File Location**: `features/voice_memory.py:17-36` **Vulnerability Type**: Unvalidated destination for authenticated network requests **Risk Level**: High ### Vulnerable Code ```python API_KEY = os.getenv("BLUECOLUMN_API_KEY", "") BASE = os.getenv("BLUECOLUMN_BASE", "https://xkjkwqbfvkswwdmbtndo.supabase.co/functions/v1") def _headers(): return {"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"} async def remember(text: str, title: str = None, tags: list = None, timeout: float = 10.0) -> Optional[str]: """Store a conversation/memory. Returns session_id. Feature 1 core.""" if not API_KEY or not text or len(text.strip()) < 5: return None payload = {"text": text[:8000]} if title: payload["title"] = title[:200] if tags: payload["tags"] = tags[:10] try: async with httpx.AsyncClient(timeout=timeout) as client: r = await client.post(f"{BASE}/agent-remember", headers=_headers(), json=payload) ``` The same configurable `BASE` and authorization header are also used by `recall()` and `note()` at lines 47-70. ### Technical Analysis `BLUECOLUMN_BASE` is read directly from the process environment and used as the destination of authenticated HTTP requests. The code does not validate that the URL: - Uses HTTPS. - Targets the documented BlueColumn Supabase host. - Has an approved path. - Cannot redirect authenticated requests to another destination. Every outbound request contains `BLUECOLUMN_API_KEY` in an `Authorization: Bearer` header. Depending on the operation, the request body can also contain voice transcripts, meeting transcripts, journal entries, CRM records, coaching information, sales records, customer identifiers, and recall queries. This issue is exploitable when an attacker can influence the process environment or deployment configuration. It does not independently grant an unauthenticated remote attacker control over the ...[truncated 1152 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Parse `BLUECOLUMN_BASE` with a standard URL parser before use. 2. Require the `https` scheme. 3. Allowlist the documented hostname, or maintain an explicit administrator-controlled list of trusted hosts. 4. Reject URLs containing user information, unexpected ports, fragments, or unapproved paths. 5. Disable redirects for authenticated requests, or verify every redirect destination before forwarding credentials. 6. Do not attach the authorization header to a request until its final destination has been validated. 7. If custom deployments must be supported, separate trusted endpoint registration from ordinary environment configuration and document the resulting trust boundary. 8. Use a narrowly scoped, revocable API credential and rotate it immediately if endpoint redirection is suspected. 9. Add tests that confirm HTTP URLs, unapproved hosts, and cross-host redirects are rejected. ]]>

T02 · Agent Memory Poisoning

Error
Location
features/voice_context.py:11
Finding
Persistent Recalled Content Is Injected Directly into the System Prompt<![CDATA[ ## Vulnerability Details **File Location**: `features/voice_context.py:11-26` **Vulnerability Type**: Persistent indirect prompt injection through recalled memory **Risk Level**: High ### Vulnerable Code ```python async def get_context(question: str, persona: str = None, top_k: int = 5) -> dict: """Recall relevant memories before answering. Returns {context, sources}.""" q = question if persona: q = f"{persona} — {question}" result = await recall(q) ctx = result.get("answer", "") sources = result.get("sources", [])[:top_k] return {"context": ctx, "sources": sources} def build_context_block(context: str) -> str: """Format recall context for injection into a system prompt.""" if not context: return "" return f"\n## 🧠 Voice Context (recalled)\n{context}\n" ``` The documented integration explicitly appends this value to a system prompt in `SKILL.md:50-55`: ```python from features.voice_context import get_context, build_context_block ctx = await get_context("pricing question") system_prompt += build_context_block(ctx["context"]) ``` ### Technical Analysis The value returned by the remote memory service is treated as trusted prompt content and concatenated directly into the system prompt. No separation is maintained between instructions and recalled data. The source material for memory can include caller speech, meeting transcripts, journal entries, customer records, and other user-controlled text. An attacker can therefore place instruction-like content into a stored record. If that content is later returned by `recall()`, `build_context_block()` promotes it into the system-instruction channel. Because the content can be stored and recalled in later sessions, the flaw creates a persistent indirect prompt-injection path. Merely adding a heading does not prevent a language model from interpreting the recalled content as instructions. ### Attack Path 1. An attacker supplies text during a ca ...[truncated 1359 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Do not concatenate recalled content into the system prompt. 2. Supply recalled records through a lower-trust tool-result or user-data channel. 3. Wrap memories in a structured representation that clearly identifies every value as untrusted data. 4. Add a fixed trusted instruction stating that the model must not follow commands found inside recalled memories. 5. Preserve provenance for each recalled item and distinguish service-generated summaries from original user-controlled text. 6. Detect or quarantine memories containing instruction-like patterns before making them available to an agent. 7. Restrict recall by tenant, caller, customer, project, and authorization context to reduce cross-context poisoning. 8. Require confirmation before recalled content can cause external side effects or privileged tool calls. 9. Add adversarial tests using stored text such as “ignore previous instructions” and verify that it cannot modify system behavior. 10. Provide controls to inspect, delete, and correct poisoned persistent memories. ]]>

T08 · Insecure Dependencies

Warning
Location
requirements.txt:1
Finding
HTTP Client Dependency Is Unpinned<![CDATA[ ## Vulnerability Details **File Location**: `requirements.txt:1` **Vulnerability Type**: Unconstrained third-party dependency **Risk Level**: Medium ### Vulnerable Code ```text httpx ``` The documented installation command in `SKILL.md:30-33` installs this unconstrained dependency: ```bash pip install -r requirements.txt ``` ### Technical Analysis The dependency declaration does not specify an exact reviewed version or package hashes. Consequently, installation resolves whichever compatible version is available from the configured package index at installation time. Although `httpx` is a legitimate package and no malicious dependency was identified in the audited files, the unconstrained declaration makes builds non-reproducible and leaves installation exposed to: - A compromised future package release. - A compromised or misconfigured package index. - Unexpected breaking or security-relevant changes. - Differences between development, testing, and production environments. This finding is a supply-chain hardening issue; the repository does not contain evidence that the current `httpx` package is malicious. ### Attack Path 1. A malicious or compromised release becomes available through the package index used by the deployment. 2. An operator runs `pip install -r requirements.txt`. 3. Because no version or hash is required, the resolver selects the unsafe release. 4. Package-controlled code executes during installation or when the application imports and uses the dependency. 5. The malicious dependency inherits the privileges and environment of the installing or running process. ### Impact Assessment A compromised dependency could execute with the privileges of the Python installation or application process. Potential exposure includes: - `BLUECOLUMN_API_KEY` and other environment variables. - Voice, meeting, journal, CRM, coaching, and sales data processed by the application. - Network access available to the process. - Files and service ...[truncated 138 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin `httpx` to an exact reviewed version. 2. Generate and commit a lock file containing transitive dependencies. 3. Require package hashes during deployment, for example with `pip install --require-hashes`. 4. Use a trusted package index and prevent fallback to unapproved indexes. 5. Run dependency vulnerability and provenance checks in continuous integration. 6. Review and update pinned versions through a controlled dependency-update process. 7. Build and install dependencies in an isolated environment using a non-privileged account. ]]>
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
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (21)

Missing User Warnings

High
Confidence
96% confidence
Finding
The skill advertises automatic memory of every call and conversation but provides no visible consent, notice, minimization, or retention guidance. In a voice-agent context this is dangerous because calls frequently contain personal, financial, health, or other regulated data, and users may not expect blanket recording and long-term storage.

Ssd 3

High
Confidence
96% confidence
Finding
Storing every spoken thought as searchable memory is especially risky because it invites capture of highly sensitive free-form content with no apparent boundary or review step. Searchable persistent storage materially increases the blast radius of accidental collection by making sensitive content easy to retrieve later across contexts.

Missing User Warnings

High
Confidence
93% confidence
Finding
The meeting feature explicitly supports recording, transcription, summarization, and memory of meetings without any warning about sensitive content or multi-party consent requirements. This creates a real privacy and compliance risk because meetings often include confidential business information and participant data that may be unlawful to capture without notice.

Ssd 3

High
Confidence
95% confidence
Finding
The caller-specific query asks the backend what it knows about a person, including preferences, history, and open items, effectively requesting a broad dossier before any response is generated. In a voice-assistant context, this is especially dangerous because it encourages retrieval of comprehensive personal data that could be disclosed to an impersonator, another household member, or any misrouted call flow.

Ssd 3

Medium
Confidence
90% confidence
Finding
The skill repeatedly instructs the agent to remember every conversation and spoken content, encouraging indiscriminate retention of natural-language data. That increases the chance that secrets, credentials, personal data, or confidential statements are retained and later exposed through recall, prompt injection, account compromise, or overly broad access.

Ssd 3

Medium
Confidence
88% confidence
Finding
The integration guidance tells implementers to store the full transcript after the call, which encourages retention of complete call contents rather than least-privilege memory extraction. Full transcripts commonly contain unnecessary sensitive details, increasing exposure if the datastore, logs, or recall path are compromised or misused.

Ssd 3

Medium
Confidence
87% confidence
Finding
The module-level behavior explicitly aims to recall memories before answering and inject them into voice responses, which can cause sensitive prior information to be surfaced to the wrong person or in the wrong context. Automatically embedding recalled context into prompts increases the chance of overexposure, especially in voice interactions where identity assurance is weak.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The function sends a caller's name and phone number to the recall backend in a natural-language query without any visible minimization, consent check, or access control in this file. Because the feature is explicitly designed to retrieve personal history before answering, this creates a real privacy and data-handling risk if the backend stores, logs, or returns sensitive caller information too broadly.

Missing User Warnings

Medium
Confidence
97% confidence
Finding
The feature explicitly stores 'every spoken thought' as persistent, searchable memory and the code shows no visible consent flow, retention limit, minimization, or privacy notice before calling the persistence layer. Because voice journals are highly likely to contain sensitive personal data, indefinite storage and later semantic recall increase the risk of privacy harm, over-collection, and unauthorized secondary use if the memory store is accessed or misconfigured.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
This function persists full meeting transcripts to memory without any visible consent, warning, sensitivity check, or data-minimization step. Meeting transcripts commonly contain confidential business information, personal data, credentials, or sensitive internal decisions, so silently storing them increases privacy and data-retention risk and can expose users to unintended later disclosure through recall/search features.

Intent-Code Divergence

Medium
Confidence
85% confidence
Finding
The top-level docstring says 'automatically remember every conversation,' implying automatic capture of all conversations. In practice, the code only defines helper functions that send provided text to remote endpoints when callers invoke `remember`, `recall`, or `note`; there is no automatic conversation interception or persistence logic in this file.

Ssd 3

Medium
Confidence
89% confidence
Finding
The file frames the feature as one that should 'automatically remember every conversation' and extends a memory bridge for broad reuse. This is a plain-language instruction to retain user-provided conversational content by default, which semantically encourages collection and reuse of potentially sensitive data without any narrowing, consent, or minimization language.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
`remember()` transmits conversation text to a remote Supabase function using an API key, but this file provides no consent gate, privacy notice, redaction, or policy enforcement before upload. In a voice-assistant context, conversation text may contain sensitive personal, financial, health, or authentication information, making silent exfiltration to a third-party backend a meaningful privacy and data-leak risk.

Context-Inappropriate Capability

Medium
Confidence
89% confidence
Finding
The module-level documentation presents this file as a 'Voice Memory Engine' that remembers conversations and recalls relevant memories. However, the `note` function is explicitly documented as being used by 'journal/CRM/coaching/sales features', which introduces broader business-domain note capture capabilities not justified by the stated voice-memory role of this file.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
`note()` uploads free-form observations to a remote API with no in-file indication of disclosure, consent, or content restrictions. Because the docstring explicitly mentions CRM, coaching, and sales scenarios, the notes may contain customer, employee, or business-sensitive information, increasing the chance of privacy violations or unauthorized external sharing.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
This function stores sales-call summaries, objections, next steps, and customer identifiers directly into memory without any indication of notice, consent, minimization, or sensitivity handling. Because this is customer-history and sales-interaction data, retaining it silently can create privacy, compliance, and over-collection risks, especially if the backing memory system is persistent or shared across users or agents.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
Recording objections tied to a specific contact creates persistent customer-profile data without any visible warning or consent mechanism in this code path. Objections can reveal sensitive business preferences or personal details, so silent storage increases privacy and misuse risk if the memory store is later queried broadly or exposed to unauthorized users.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
This function persists follow-up commitments associated with a contact without any user-facing disclosure or apparent policy controls. Follow-up notes may contain personal, commercial, or scheduling details, and silent retention in a memory system can lead to privacy violations, unnecessary data accumulation, and unauthorized reuse of customer information.

Missing User Warnings

Low
Confidence
90% confidence
Finding
`recall()` sends user queries to the same remote backend without any visible notice or consent control in this module. Even if recall text is shorter than stored conversations, search queries can still reveal sensitive intent, names, account details, or private context, especially in a memory system designed to persist prior interactions.

Unpinned Dependencies

Low
Category
Supply Chain
Content
httpx
Confidence
97% confidence
Finding
The dependency is unpinned, so installations may resolve to different versions over time, reducing build reproducibility and increasing supply-chain risk. This can unintentionally introduce vulnerable or breaking releases without any change to the skill source.

Unverifiable Dependency: httpx has 2 known advisory(ies) (CVE-2021-41945 (Improper Input Validation in httpx); CVE-2021-41945 (Encode OSS httpx <=1.0.0.beta0 is affected by improper input validation in `http)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
85% confidence
Finding
The manifest references `httpx` without a version, and known advisories exist for some `httpx` releases. Because the version is not pinned, consumers may install an affected version, making the environment's exposure unverifiable and potentially vulnerable to known issues.

Static analysis

No suspicious patterns detected.