T09 · Insecure Skill Coding Practices
- Location
hooks/emotion-state/handler.ts:269- Finding
Full Conversation Content and API Credentials Can Be Sent to Arbitrary Network Endpoints
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill’s emotion-tracking purpose is real, but it handles conversation text, persistent profiles, prompt injection, and cross-agent state with insufficient boundaries.
Review before installing. Only use this skill where users and agents have consented to emotion profiling, persistent state, and prompt influence. Prefer a trusted local or tightly allowlisted classifier, avoid arbitrary OPENAI_BASE_URL values, restrict filesystem access between agents, and add deletion/retention controls before using it with sensitive conversations.
hooks/emotion-state/handler.ts:269Full Conversation Content and API Credentials Can Be Sent to Arbitrary Network Endpoints
hooks/emotion-state/handler.ts:325Untrusted Classifier Output Is Persisted and Injected into Bootstrap Prompt Material
hooks/emotion-state/handler.ts:429Cross-Agent Emotion State Is Read and Exposed Without an Explicit Isolation Boundary
The documented behavior goes beyond the apparent purpose by persisting emotion state across sessions, reading agent state, and sending conversation-derived data to external classifier endpoints, while those capabilities are not clearly declared up front. This mismatch can mislead users into installing a component with broader data access and retention than expected, increasing privacy and prompt-manipulation risk.
The code reads OPENAI_API_KEY and sends raw conversation text to an external classifier/OpenAI endpoint for emotion analysis. This is dangerous because user and assistant messages may contain secrets, personal data, or system prompts, and the skill exports that content off-box without minimization or clear necessity beyond local state tracking.
Skill manipulates agent memory, state, or stored context. Memory corruption can alter personality, override safety rules, or cause unpredictable behavior.
.sort((a, b) => (a.ts < b.ts ? -1 : a.ts > b.ts ? 1 : 0));
const toRemove = sorted.slice(0, keys.length - maxUsers);
for (const { key } of toRemove) {
delete state.users[key];
}
}
The skill advertises hook installation and configuration that clearly require environment access and outbound network capability, yet it declares no explicit tool scope or permissions. This weakens reviewability and consent, making it easier for a skill to access sensitive configuration and external services without clear operator awareness.
Persisting inferred emotion data across sessions and injecting it into the system prompt changes future model behavior based on stored user profiling, but the description does not present this as a clear warning or consent point. In this context, hidden persistence plus prompt injection is especially sensitive because it can silently influence later interactions and expose private inferences beyond the original session.
The configuration directs operators to use OpenAI or another classifier endpoint but does not clearly warn that conversation-derived emotional inferences may be sent to a third party. This creates a data handling and privacy risk because users may not realize sensitive behavioral profiling leaves the local environment.
The explicit external API base URL indicates the skill can transmit data to a third-party service. In a skill that analyzes and stores inferred emotional state, outbound transmission is more dangerous than ordinary telemetry because it may expose sensitive user profiling data and model-derived context to an external processor.
"env": {
"EMOTION_CLASSIFIER_URL": "",
"OPENAI_API_KEY": "YOUR_KEY",
"OPENAI_BASE_URL": "https://api.openai.com/v1",
"EMOTION_MODEL": "gpt-4o-mini",
"EMOTION_CONFIDENCE_MIN": "0.35",
"EMOTION_HISTORY_SIZE": "100",
The hook documentation describes collecting, persisting, and later injecting emotional assessments into the system prompt, but it does not clearly warn users that these assessments may be stored in per-agent state and transmitted to external classifiers or OpenAI. This creates a meaningful privacy and transparency risk because sensitive inferred psychological data could be retained and exfiltrated without informed operator consent.
The hook is explicitly configured to send emotion-related content to an external HTTP endpoint or OpenAI when enabled. Because the content consists of inferred user/agent emotional state, this can expose sensitive behavioral or psychological data to third parties, and the risk is amplified by the hook's bootstrap-time prompt injection role, which may cause broad propagation of those inferences into subsequent model context.
- `EMOTION_CLASSIFIER_URL`: Optional HTTP endpoint for classification.
- `OPENAI_API_KEY`: If set and no classifier URL, the hook calls OpenAI.
- `OPENAI_BASE_URL`: Default `https://api.openai.com/v1`.
- `EMOTION_MODEL`: Model name for OpenAI (default `gpt-4o-mini`).
- `EMOTION_CONFIDENCE_MIN`: Default `0.35`.
- `EMOTION_HISTORY_SIZE`: Default `100`.
The skill persists conversation-derived emotional profiles to disk in a predictable location, but there is no visible notice, retention policy enforcement, or access control in this file. Persistent profiling can outlive a session and expose sensitive inferences if local files are read by other skills, users, or processes.
The configurable classifier endpoint receives message content with no visible disclosure, consent, or trust restrictions in this code path. Because the URL is environment-controlled, the skill can silently exfiltrate conversation data to arbitrary infrastructure, increasing privacy and compliance risk.
The OpenAI call ships conversation content to a third-party service without any visible user-facing warning or consent mechanism. In this skill context, message text is harvested automatically during bootstrap, so users may be unaware that their content is being analyzed and retained externally.
This is a concrete external transmission sink to the OpenAI API, carrying message text from the session to a network service. In the context of an emotion-tracking bootstrap hook, automatic egress of conversation content is particularly sensitive because it processes potentially private user inputs without strong boundaries or minimization.
async function classifyWithOpenAI(text: string, role: string, model: string) {
const apiKey = envString("OPENAI_API_KEY");
if (!apiKey) throw new Error("Missing OPENAI_API_KEY");
const baseUrl = envString("OPENAI_BASE_URL", "https://api.openai.com/v1");
const timeoutMs = envNumber("EMOTION_FETCH_TIMEOUT_MS", DEFAULTS.fetchTimeoutMs);
const systemPrompt =
"You are an emotion classifier. Return only JSON with keys: label, intensity, reason, confidence. " +
The hook enumerates sibling agent directories and imports their latest emotional state into the current agent's bootstrap context, creating unauthorized cross-agent data access. In an agent platform, this breaks isolation boundaries and can expose private conversation-derived profiles from unrelated agents to prompts and downstream model behavior.
The code forces the 'en-CA' locale for formatting timestamps, which is a natural-language/locale choice applied regardless of user preference. There is no indication here that users can opt into this locale or that the locale restriction is justified by a region-specific requirement.
Detected: suspicious.env_credential_access