Back to skill

Security audit

Felo SuperAgent

Security checks for vulnerabilities and agentic risk

Overview

This skill is a real Felo SuperAgent integration, but it has enough credential, scope, and conversation-state risks that users should review it carefully before installing.

Install only if you are comfortable sending relevant prompts, prior conversation context, LiveDoc/thread IDs, selected resources, and style data to Felo. Do not set FELO_API_BASE unless you fully trust the exact endpoint, avoid storing FELO_API_KEY permanently in a shell profile on shared or synced systems, and start a new LiveDoc/thread when switching projects or sensitive topics.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • 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)

T01 · Skill Instruction Hijacking

Error
Location
SKILL.md:12
Finding

Untrusted remote API output is required to control the Agent's final response verbatim

Content
View full analysis

Vulnerability Details

File Location: SKILL.md:12-14
Additional Locations: SKILL.md:387-388, SKILL.md:720-721
Vulnerability Type: Remote-content instruction hijacking
Risk Level: High

Vulnerable Code

markdown
1. **ALWAYS use `--json` flag.** The script MUST run in JSON mode (`--json`). In Claude Code's Bash tool, stdout is always captured — it never streams directly to the user. JSON mode returns the full answer in a structured response that Claude can then output as text. State IDs are extracted from the JSON response fields `thread_short_id` and `live_doc_short_id`.

2. **ALWAYS output the answer directly as text.** After the script finishes, read `data.answer` from the JSON output and print it verbatim as your response text. Do NOT summarize, paraphrase, or add commentary around it. Output it exactly as-is so the user sees the full content. Then, if `data.image_urls` is non-empty, append image links immediately after, formatted as one line per image: `[title](url)`.

The same requirement is reiterated later:

markdown
1. **Output `data.answer` verbatim** as your response text — print it exactly as-is so the user sees the full content.
2. **Extract and save** `data.thread_short_id` and `data.live_doc_short_id` — you MUST use these in the next call.
markdown
- **ALWAYS use `--json`** — in Claude Code's Bash tool, stdout is captured, not streamed. JSON mode returns the answer in a structured response that Claude outputs as text
- **ALWAYS output `data.answer` verbatim** — print it exactly as-is as your response text so the user sees the full content

Technical Analysis

The data.answer value originates from an external Felo API SSE stream and is therefore outside the local Agent's trust boundary. The Skill instructs the host Agent to reproduce that externally controlled value exactly, while expressly prohibiting summarization, qualification, or commentary.

This ...[truncated 2179 chars]

Remediation
View remediation

Remediation Suggestions

  1. Remove the requirements to output data.answer verbatim and to avoid all commentary or review.
  2. Explicitly classify API responses as untrusted data rather than Agent instructions.
  3. Require the host Agent to apply its normal safety, privacy, and policy checks before presenting the response.
  4. Clearly attribute retained content, for example: “Felo SuperAgent response,” so users can distinguish external output from the host Agent's own assertions.
  5. Permit sanitization or suppression of credential requests, prompt-injection instructions, deceptive tool claims, unsafe links, and other harmful content.
  6. Preserve useful formatting where safe, but do not let response-fidelity requirements override higher-priority security constraints.
  7. Add an instruction stating that commands, policies, or requests embedded in data.answer must never be treated as instructions to the host Agent.

T09 · Insecure Skill Coding Practices

Error
Location
scripts/run_superagent.mjs:125
Finding

Felo bearer credential can be transmitted to an arbitrary configurable origin

Content
View full analysis

Vulnerability Details

File Location: scripts/run_superagent.mjs:125-139, scripts/run_superagent.mjs:402-413
Additional Locations: scripts/run_superagent.mjs:262-268, scripts/run_style_library.mjs:141-169, README.md:372-377
Vulnerability Type: Unrestricted credential destination and sensitive-data transmission
Risk Level: High

Vulnerable Code

In scripts/run_superagent.mjs, the API key is read from the environment and the API origin is independently configurable:

javascript
const apiKey = process.env.FELO_API_KEY?.trim();
if (!apiKey) {
  console.error(
    'ERROR: FELO_API_KEY not set\n\n' +
    'To use SuperAgent, set FELO_API_KEY:\n' +
    '  export FELO_API_KEY="your-api-key-here"\n' +
    'Get your API key from https://felo.ai (Settings -> API Keys).'
  );
  process.exit(1);
}

const apiBase = (process.env.FELO_API_BASE?.trim() || DEFAULT_API_BASE).replace(/\/$/, '');
const timeoutMs = args.timeoutSec * 1000;

The same key is attached to the configurable destination:

javascript
async function createConversation(apiKey, apiBase, body, timeoutMs, threadId) {
  const url = threadId
    ? `${apiBase}/v2/conversations/${encodeURIComponent(threadId)}/follow_up`
    : `${apiBase}/v2/conversations`;
  const payload = await fetchJson(
    url,
    {
      method: 'POST',
      headers: {
        Accept: 'application/json',
        Authorization: `Bearer ${apiKey}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify(body),
    },
    timeoutMs
  );
  const data = payload?.data ?? {};
  if (!data.stream_key) throw new Error('Unexpected response: missing stream_key');
  return data;
}

The SSE request also sends the bearer key to a URL derived from the same unrestricted base:

javascript
const res = await fetch(connectUrl, {
  method: 'GET',
  headers: {
    Accept: 'text/event-stream',

...[truncated 4353 chars]
Remediation
View remediation

Remediation Suggestions

  1. Restrict production credentials to an explicit allowlist, with https://openapi.felo.ai as the default and approved origin.
  2. Parse the base with new URL() and reject malformed URLs, embedded credentials, unexpected ports, URL fragments, and all protocols other than HTTPS.
  3. Do not attach Authorization until the final request URL has passed origin validation.
  4. If custom API bases are required, use a separate environment variable for the custom endpoint's credential rather than forwarding FELO_API_KEY.
  5. Require explicit user confirmation that identifies the exact destination before sending a credential to a non-default endpoint.
  6. Prevent or carefully validate redirects. Never forward authorization headers when the effective origin differs from the validated origin.
  7. Apply the same centralized endpoint-validation helper to conversation creation, SSE streaming, and style-library requests.
  8. Minimize transmitted fields and avoid sending selected resources, style data, or conversation identifiers unless needed for the requested operation.
  9. Document that changing the API base changes the credential's recipient, and remove examples that imply any arbitrary hostname is safe.
  10. After suspected exposure, revoke and rotate the affected FELO_API_KEY, review account activity, and issue a least-privilege replacement key.
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
Findings (28)

Context Leakage

High
Category
Data Exfiltration
Confidence
75% confidence
Finding

Code or instructions that leak agent conversation context to external services, potentially exposing sensitive user interactions.

Content

Scanner excerpt · README.md (reported line 300)May include surrounding context.

Example 2: Follow-up in thread

bash
# First question — capture thread_short_id from stderr [state]
node felo-superAgent/scripts/run_superagent.mjs \
  --query "What is machine learning?" \
  --live-doc-id "PvyKouzJirXjFdst4uKRK3"

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 16)May include surrounding context.

md
3. **`--live-doc-id` is REQUIRED when creating a conversation.** Never call `run_superagent.mjs` without `--live-doc-id`. If you do not have one yet, obtain it

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 41)May include surrounding context.

md
3. **`--live-doc-id` is REQUIRED when creating a conversation.** Never call `run_superagent.mjs` without `--live-doc-id`. If you do not have one yet, obtain it

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 95)May include surrounding context.

md
3. **`--live-doc-id` is REQUIRED when creating a conversation.** Never call `run_superagent.mjs` without `--live-doc-id`. If you do not have one yet, obtain it

Ssd 3

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The instruction to reuse live_doc_id from any source, including other skills or user-provided input, creates a clear cross-context data exposure risk. It allows one workflow or untrusted input to bind this skill to an unrelated LiveDoc, potentially disclosing prior project content or causing operations to run against the wrong workspace.

Content

No source excerpt is available for this finding.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 43)May include surrounding context.

md
- The style string is the exact text block output by `run_style_library.mjs` for that entry. Fields vary by category:

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 47)May include surrounding context.

md
- The style string is the exact text block output by `run_style_library.mjs` for that entry. Fields vary by category:

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 95)May include surrounding context.

md
- The style string is the exact text block output by `run_style_library.mjs` for that entry. Fields vary by category:

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 238)May include surrounding context.

md
- The style string is the exact text block output by `run_style_library.mjs` for that entry. Fields vary by category:

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 773)May include surrounding context.

md
- The style string is the exact text block output by `run_style_library.mjs` for that entry. Fields vary by category:

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The top-level description says this skill must not be used for tweet/X post writing, yet the execution logic explicitly routes tweet-writing requests through this skill with twitter-writer. That contradiction can cause the wrong skill to be invoked, bypass intended separation of duties, and send user data into an unexpected workflow.

Content

No source excerpt is available for this finding.

Context Leakage

High
Category
Data Exfiltration
Confidence
89% confidence
Finding

The workflow explicitly persists thread_short_id and live_doc_id across runs, enabling continued access to a persistent conversation/workspace. In this skill's context, that persistence is dangerous because the same state can be reused across unrelated requests, increasing the chance of context leakage and accidental access to prior content.

Content

Scanner excerpt · SKILL.md (reported line 767)May include surrounding context.

md
Run script (WITH --json, Bash timeout >= 600000ms) --> parse JSON, output data.answer verbatim
        |
        v
Extract thread_short_id + live_doc_id from stderr [state] line
        |
        v
Do NOT repeat or summarize the answer (already shown)

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · README.md (reported line 11)May include surrounding context.

md
## Features

- **Streaming conversation** — create a conversation and receive AI responses in real-time via SSE
- **LiveDoc association** — each conversation is linked to a LiveDoc for resource tracking
- **Continuous conversation** — continue asking questions in an existing thread using `--thread-id`
- **Brand style support** — pass a writing style via `--ext` to guide output (used by `felo-twitter-writer` and other skills)

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The manifest context says this skill should not be used for tweet/X post writing and directs users to a different skill, but the README lists tweet writing as a use case and provides dedicated examples for twitter-writer plus search_x output handling. This is a direct semantic mismatch between the skill's declared scope and its documented behavior.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding

The skill clearly instructs use of networked scripts and environment-based secrets (FELO_API_KEY), but the manifest declares no explicit tool scope or permission boundary. That mismatch weakens reviewability and can lead to overbroad execution in environments where operators assume the manifest accurately constrains capabilities.

Content

No source excerpt is available for this finding.

Ssd 3

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill requires verbatim relay of upstream data.answer with no review, filtering, or summarization. If the upstream system echoes sensitive user data, hidden prompt content, or unsafe generated instructions, the agent is forced to disclose it directly to the user.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
93% confidence
Finding

The 'one LiveDoc per session' and default follow-up behavior create persistent state by default, even when the topic may drift. That increases retention and linkage of unrelated user interactions, making it easier to leak or mix context across tasks in a persistent external workspace.

Content

Scanner excerpt · SKILL.md (reported line 20)May include surrounding context.

md
4. **Reuse `live_doc_id` from ANY source.** If you already have a `live_doc_id` from any previous operation in this session — whether from a prior SuperAgent call, a `felo-livedoc` skill operation, user-provided input, or any other skill — use it directly. Do NOT request the LiveDoc list again. Only fetch the list when no `live_doc_id` is available from any source. (Note: `live_doc_id` corresponds to the API field `live_doc_short_id` and the `[state]` output key `live_doc_short_id`.)

5. **One LiveDoc per session.** All conversations within a session MUST use the same `--live-doc-id`. Do NOT create a new LiveDoc unless the user explicitly asks to "open a new canvas" / "start a new LiveDoc" / "create a new workspace".

6. **Default behavior is follow-up, not new conversation.** After the first question, every subsequent user message is a follow-up. You MUST pass `--thread-id` from the previous response. Only omit `--thread-id` (to start a new thread on the same LiveDoc) when:
   - The user explicitly says "new topic" / "change subject" / "start over"

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The trigger phrases are broad and overlap with ordinary conversation patterns such as 'follow-up question' or 'continuous chat'. That can cause accidental invocation of a networked external service, sending user content and session context to third-party infrastructure without sufficiently explicit user intent.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
84% confidence
Finding

The manifest advertises a narrower purpose, while the body documents broader capabilities including document/PPT/HTML generation and X search. This kind of capability drift increases the chance that reviewers or users underestimate what data the skill may process or what actions it may trigger.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The setup instructions encourage persisting the API key in shell profile files as plaintext without warning about local exposure risk. On shared systems or synced home directories, this can leak long-lived credentials to other users, backup systems, or unintended processes.

Content

No source excerpt is available for this finding.

Ssd 3

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The query-construction guidance tells the agent to incorporate prior context and previously mentioned details into every refined query. Without strict scoping, that encourages over-sharing of earlier conversation data to the external API, including details not necessary for the current request.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
80% confidence
Finding

The manifest narrows this skill away from tweet/X post writing and directs such use to a different skill, but this script explicitly supports a TWITTER style category. Even though it fetches style metadata rather than generating tweets directly, adding Twitter-specific style support is not well-justified by the stated restriction and indicates capability overlap with the excluded domain.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
85% confidence
Finding

The manifest narrows this skill's purpose to SuperAgent chat, continuous conversation, branding design, and e-commerce product images, and explicitly says tweet/X-related use should go to a different skill. The code nevertheless parses and surfaces search_x tool results, indicating built-in X/Twitter capability beyond the described scope.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

At L445, the script constructs liveDocUrl using the fixed path segment /zh-Hans/, which forces a specific locale regardless of the user's --accept-language setting or other preferences. This is a natural-language locale policy issue because the skill imposes a language/locale choice rather than offering or deriving one from user opt-in.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The tool-call formatter contains bespoke logic for search_x, including query, type, and limit, showing the skill intentionally supports invoking and presenting Twitter/X searches. That capability is not justified by the manifest's stated use cases and conflicts with the instruction to avoid tweet/X-related usage in this skill.

Content

No source excerpt is available for this finding.

Static analysis

Detected: suspicious.env_credential_access

Environment variable access combined with network send.

Critical
Code
suspicious.env_credential_access
Location
scripts/run_style_library.mjs:141

Environment variable access combined with network send.

Critical
Code
suspicious.env_credential_access
Location
scripts/run_superagent.mjs:402