T05 · Unauthorized Access and Privilege Escalation
- Location
SKILL.md:182- Finding
Routine Operations Use an Unrestricted Supabase Service-Role Credential
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill is a disclosed personal knowledge-base integration, but it asks the agent to handle private notes with a full Supabase service-role key and automatic LLM-driven database writes.
Install only if you are comfortable sending captured notes, names, tasks, and action items to OpenRouter and storing them in Supabase. Use a dedicated Supabase project, keep service-role credentials out of shared or client environments, avoid capturing secrets or regulated data, and prefer a scoped backend or restricted database role before using this with broad personal or work data.
SKILL.md:182Routine Operations Use an Unrestricted Supabase Service-Role Credential
references/ingest.md:37Untrusted LLM Classification Output Directly Controls Privileged Database Writes
Using a high-privilege service-role key for broad retrieval operations without an explicit warning about its sensitivity materially increases the chance users will paste it into local scripts, agent configs, or front-end code. Because this key can bypass RLS and access the entire knowledge base, accidental exposure would grant an attacker extensive access to personal and potentially sensitive stored data.
The skill description encourages broad capture of user-provided information from many sources into a centralized, persistent system. This creates a surveillance-style data aggregation risk where personal, relationship, and task data are collected and retained beyond what is strictly necessary.
This call transmits raw captured thought content to an external embeddings provider. While embeddings are part of the advertised functionality, sending unfiltered personal text off-platform introduces confidentiality and compliance risks, especially when the system is designed to ingest personal notes from arbitrary sources.
# 1. Embed
EMBEDDING=$(curl -s -X POST "https://openrouter.ai/api/v1/embeddings" \
-H "Authorization: Bearer $OPENROUTER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model": "openai/text-embedding-3-small", "input": "Sarah mentioned she is thinking about leaving her job to start consulting"}' \
This classification request sends the full captured thought to an external LLM along with instructions to extract people, action items, and structured metadata. That increases exposure because it not only transfers the content itself, but also prompts derivation of additional sensitive inferences that may reveal relationships, intentions, or plans.
| jq -c '.data[0].embedding')
# 2. Classify (run in parallel with step 1)
METADATA=$(curl -s -X POST "https://openrouter.ai/api/v1/chat/completions" \
-H "Authorization: Bearer $OPENROUTER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model": "openai/gpt-4o-mini", "response_format": {"type": "json_object"}, "messages": [{"role": "system", "content": "Extract metadata from the captured thought. Return JSON with: type (observation/task/idea/reference/person_note), topics (1-3 tags), people (array), action_items (array), dates_mentioned (array), confidence (0-1), suggested_route (people/projects/ideas/admin/null), extracted_fields (structured data for destination table)."}, {"role": "user", "content": "Sarah mentioned she is thinking about leaving her job to start consulting"}]}' \
This step persists the captured thought, embedding, and metadata to Supabase using a service_role key that bypasses row-level security. In the context of an agent skill, use of a full-privilege credential raises the impact of any prompt injection, environment leakage, or downstream misuse because the key can read and write all records.
| jq -r '.choices[0].message.content')
# 3. Store in thoughts (the Receipt)
curl -s -X POST "$SUPABASE_URL/rest/v1/thoughts" \
-H "apikey: $SUPABASE_SERVICE_ROLE_KEY" \
-H "Authorization: Bearer $SUPABASE_SERVICE_ROLE_KEY" \
-H "Content-Type: application/json" \
The skill explicitly requires persistent logging of every captured thought and associated metadata, creating a durable audit trail of potentially sensitive personal information. Even if intended for a personal knowledge base, mandatory retention increases privacy risk, blast radius from compromise, and the chance of storing data the user did not mean to preserve.
The skill states that all captured text, names, and action items are sent to OpenRouter for embedding and classification, which is a clear third-party disclosure of potentially sensitive personal data. Because the content includes relationship notes, tasks, and observations, this can expose intimate or confidential information to an external processor and expand the trust boundary significantly.
The document identifies OpenRouter as the compute layer used for classification, but does not disclose that captured user content may be transmitted to an external AI provider for processing. In this context, that omission is dangerous because the system is designed to ingest free-form personal notes and messages, so users may unknowingly send sensitive data outside their primary storage boundary.
The skill explicitly encourages capturing thoughts from channels like Slack, Signal, SMS, and voice, then logging everything to a central thoughts table, but it does not warn about privacy, consent, retention, or handling of sensitive content. That creates a real privacy/security risk because users may funnel personal, regulated, or third-party data into persistent storage and downstream AI processing without understanding the consequences.
The ingest instructions explicitly send raw captured thought text to OpenRouter for embeddings and classification, but they do not require any user notice, consent, or data-minimization step before third-party transmission. Because the content can come from Signal, SMS, email, or voice, this may expose sensitive personal data to an external AI provider unexpectedly.
This step transmits the full thought text to OpenRouter's embeddings API, constituting external data exfiltration to a third party. In the context of a personal knowledge system that captures messages from private channels, this can leak sensitive personal, professional, or confidential content without explicit safeguards.
Convert the thought text into a 1536-dimensional vector via OpenRouter.
curl -s -X POST "https://openrouter.ai/api/v1/embeddings" \
-H "Authorization: Bearer $OPENROUTER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
The examples instruct use of the Supabase service-role key directly in REST calls for inserts into the thoughts table, which grants broad privileged access and bypasses normal least-privilege patterns. If this guidance is followed in an agent runtime, prompt leakage, logs, or misuse of the key could enable unrestricted reads/writes across the database.
This request sends personal data queries and uses a high-privilege service-role credential over an externally callable REST interface. While contacting Supabase is expected for app storage, the dangerous aspect is coupling sensitive person records with an all-powerful key in agent instructions, increasing blast radius if the credential is exposed or the request context is abused.
First, check if the person exists:
curl -s "$SUPABASE_URL/rest/v1/people?name=eq.Sarah&select=id,context,follow_ups" \
-H "apikey: $SUPABASE_SERVICE_ROLE_KEY" \
-H "Authorization: Bearer $SUPABASE_SERVICE_ROLE_KEY"
The thoughts-row update sends detailed metadata and routing information back to Supabase using the service-role key, again normalizing privileged direct database mutation from the agent layer. If the credential or request path is compromised, an attacker could tamper with records broadly or pivot to other tables, not just update a single thought.
After successful routing, update the thoughts row to record where it went:
curl -s -X PATCH "$SUPABASE_URL/rest/v1/thoughts?id=eq.THOUGHT_UUID" \
-H "apikey: $SUPABASE_SERVICE_ROLE_KEY" \
-H "Authorization: Bearer $SUPABASE_SERVICE_ROLE_KEY" \
-H "Content-Type: application/json" \
The batch embedding example expands the same external-transmission issue to multiple thoughts at once, increasing privacy risk and potential data exposure volume in a single operation. In a second-brain workflow, batch captures may include many private notes, making accidental oversharing to the third-party provider more damaging.
curl -s -X POST "https://openrouter.ai/api/v1/embeddings" \
-H "Authorization: Bearer $OPENROUTER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
The examples explicitly send user-provided text to a third-party API for embeddings, but the document does not warn that captured thoughts may contain sensitive personal, work, or confidential data. In a personal knowledge system, users are especially likely to submit private notes, so omission of a privacy/data-transfer notice can lead to unintentional external disclosure.
This line demonstrates an outbound POST request to OpenRouter containing user text, which is an external transmission of potentially sensitive content. In isolation, external API use is not inherently malicious, but in this skill's context the transmitted data is free-form personal knowledge, making undisclosed off-platform transfer a meaningful security and privacy risk.
curl -s -X POST "https://openrouter.ai/api/v1/embeddings" \
-H "Authorization: Bearer $OPENROUTER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
The classification flow sends the user's captured thought directly to OpenRouter for metadata extraction without disclosing the privacy implications. Because the skill is designed to ingest arbitrary personal thoughts and route them into a 'second brain,' it raises the likelihood of transmitting sensitive personal, health, financial, or employer-confidential information to an external provider.
The document explicitly tells users to use the Supabase service-role key for all retrieval operations, even though these examples are read/query flows that should normally use lower-privilege credentials or server-side mediation. Service-role keys bypass row-level security and expose full-database privileges, so reuse of this guidance in client scripts, agents, or shared environments can lead to broad unauthorized data access or destructive follow-on abuse if the key leaks.
This example transmits query content to an external embeddings provider. External transmission is expected for hosted embeddings, but in this skill's context the queries may reveal highly personal knowledge-management content, making undocumented disclosure a meaningful privacy risk rather than a harmless integration detail.
# Embed the query
QUERY_EMBEDDING=$(curl -s -X POST "https://openrouter.ai/api/v1/embeddings" \
-H "Authorization: Bearer $OPENROUTER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model": "openai/text-embedding-3-small", "input": "career changes"}' \
The semantic search examples send raw query text to OpenRouter's embeddings API without any warning that user-entered queries may contain sensitive personal knowledge, names, tasks, or internal context. In a 'second brain' skill, this context is especially privacy-sensitive, so silent third-party transmission increases the risk of inadvertent disclosure and compliance issues.
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
| jq -c '.data[0].embedding')
# Search all tables
curl -s -X POST "$SUPABASE_URL/rest/v1/rpc/search_all" \
-H "apikey: $SUPABASE_SERVICE_ROLE_KEY" \
-H "Authorization: Bearer $SUPABASE_SERVICE_ROLE_KEY" \
-H "Content-Type: application/json" \
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
-d '{"model": "openai/text-embedding-3-small", "input": "website redesign tasks"}' \
| jq -c '.data[0].embedding')
curl -s -X POST "$SUPABASE_URL/rest/v1/rpc/match_thoughts" \
-H "apikey: $SUPABASE_SERVICE_ROLE_KEY" \
-H "Authorization: Bearer $SUPABASE_SERVICE_ROLE_KEY" \
-H "Content-Type: application/json" \
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
-d '{"model": "openai/text-embedding-3-small", "input": "website redesign tasks"}' \
| jq -c '.data[0].embedding')
curl -s -X POST "$SUPABASE_URL/rest/v1/rpc/match_thoughts" \
-H "apikey: $SUPABASE_SERVICE_ROLE_KEY" \
-H "Authorization: Bearer $SUPABASE_SERVICE_ROLE_KEY" \
-H "Content-Type: application/json" \
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
-d '{"model": "openai/text-embedding-3-small", "input": "career mentors"}' \
| jq -c '.data[0].embedding')
curl -s -X POST "$SUPABASE_URL/rest/v1/rpc/match_people" \
-H "apikey: $SUPABASE_SERVICE_ROLE_KEY" \
-H "Authorization: Bearer $SUPABASE_SERVICE_ROLE_KEY" \
-H "Content-Type: application/json" \
No suspicious patterns detected.