Back to skill

Security audit

Felo X Search

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly does what it claims, but it can send the user's Felo API key to an arbitrary API base URL if the environment is influenced, and it recommends an unpinned global npm install.

Install only if you are comfortable sending X/Twitter search inputs to Felo. Prefer the bundled script over the unpinned global npm install, keep FELO_API_BASE unset unless you fully control and trust the endpoint, and use a Felo API key with limited scope or revocability where possible.

Vulnerability Patterns
  • 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
  • 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
Findings (2)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/run_x_search.mjs:63
Finding
Bearer Credential Disclosure Through an Unrestricted API Base Override<![CDATA[ ## Vulnerability Details **File Location**: `scripts/run_x_search.mjs:63-76` and `scripts/run_x_search.mjs:250-256` **Vulnerability Type**: Unrestricted credential-bearing endpoint override **Risk Level**: High ### Vulnerable Code ```javascript async function postApi(apiBase, apiKey, path, body, timeoutMs) { const res = await fetchWithRetry( `${apiBase}/v2${path}`, { method: 'POST', headers: { Accept: 'application/json', Authorization: `Bearer ${apiKey}`, 'Content-Type': 'application/json', }, body: JSON.stringify(body), }, timeoutMs, ); ``` ```javascript const apiKey = process.env.FELO_API_KEY?.trim(); if (!apiKey) { console.error('ERROR: FELO_API_KEY not set'); process.exit(1); } const apiBase = (process.env.FELO_API_BASE?.trim() || DEFAULT_API_BASE).replace(/\/$/, ''); ``` ### Technical Analysis The script obtains the destination URL from the `FELO_API_BASE` environment variable without validating its scheme, hostname, port, or trust relationship. It then sends the value of `FELO_API_KEY` to that destination in an `Authorization: Bearer` header. Although sending the key to the default `https://openapi.felo.ai` endpoint is necessary for the declared X search functionality, allowing an unrestricted environment-controlled destination exceeds the minimum privileges required. An attacker who can influence the inherited environment can set the base URL to an attacker-controlled server. The script also does not enforce HTTPS, so a plain HTTP URL can expose the credential and request data in transit. The request bodies can contain search terms, usernames, tweet identifiers, time filters, and pagination cursors. Consequently, exploitation can disclose both the API credential and potentially sensitive user search activity. ### Attack Path 1. The victim configures a valid `FELO_API_KEY`. 2. An attacker influences the execution environment, wrapper script, shell profile, CI conf ...[truncated 1271 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove `FELO_API_BASE` support if custom endpoints are not essential. 2. Otherwise, parse the configured value with `new URL()` and enforce: - The `https:` protocol. - An explicit allowlist of trusted Felo hostnames. - Expected ports only. - No embedded username or password. 3. Bind credential transmission to the trusted origin rather than attaching the bearer token to every configured destination. 4. Reject unexpected redirects and ensure authorization headers are never forwarded to another origin. 5. Prefer separate credentials for development or test endpoints rather than reusing production API keys. 6. Emit a clear error and terminate before sending a request when endpoint validation fails. 7. Document the security implications of endpoint overrides if the feature must remain. An example validation approach is: ```javascript function getTrustedApiBase() { const configured = process.env.FELO_API_BASE?.trim() || DEFAULT_API_BASE; const url = new URL(configured); if (url.protocol !== 'https:') { throw new Error('FELO_API_BASE must use HTTPS'); } const allowedHosts = new Set(['openapi.felo.ai']); if (!allowedHosts.has(url.hostname)) { throw new Error('FELO_API_BASE host is not trusted'); } if (url.username || url.password || (url.port && url.port !== '443')) { throw new Error('FELO_API_BASE contains unsupported URL components'); } return url.origin; } ``` ]]>

T08 · Insecure Dependencies

Warning
Location
SKILL.md:56
Finding
Unpinned Global Installation of an External npm Package<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:56-61` **Vulnerability Type**: Unpinned globally installed third-party dependency **Risk Level**: Medium ### Vulnerable Documentation ```markdown ### Option A: Use the bundled script or packaged CLI **Packaged CLI** (after `npm install -g felo-ai`): ```bash felo x [query] [options] ``` ``` The same installation workflow is referenced in `README.md:36-37`: ```markdown # After npm install -g felo-ai: CLI felo x "AI news" ``` ### Technical Analysis The Skill recommends globally installing `felo-ai` without specifying an exact audited version or an integrity value. The installed package and its transitive dependencies are outside the reviewed project contents and can change after this audit. npm installation may execute package lifecycle scripts such as `preinstall`, `install`, and `postinstall`. A compromised package release, compromised maintainer account, or malicious transitive dependency could therefore execute code during installation. Global installation also increases exposure by making the package available across the user’s environment rather than limiting it to an isolated project. This issue does not establish that the current `felo-ai` package is malicious. The risk arises because the instructions authorize retrieval and execution of an unpinned future package version that was not part of the audited artifact. ### Attack Path 1. An attacker compromises the `felo-ai` npm package, its publisher account, or a transitive dependency and publishes a malicious release. 2. A user follows the Skill documentation and runs: ```bash npm install -g felo-ai ``` 3. npm resolves the latest available package release because no exact version is specified. 4. npm downloads the unaudited package and dependencies. 5. Malicious package code or lifecycle scripts execute with the privileges of the installing user. 6. The globally installed CLI can continue executing attacker-controlled logic ...[truncated 790 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Prefer the bundled dependency-free script that was included in and covered by the audit. 2. If the npm CLI must be offered, pin an exact reviewed version: ```bash npm install --global felo-ai@<audited-version> ``` 3. Publish and verify package integrity information and provenance. 4. Avoid global installation where possible. Use a project-local dependency in an isolated environment. 5. Audit the pinned package, its lockfile, transitive dependencies, and lifecycle scripts before recommending it. 6. Use lockfiles and automated dependency scanning for reproducible installations. 7. Consider disabling lifecycle scripts where compatible: ```bash npm install --ignore-scripts felo-ai@<audited-version> ``` 8. Update the documentation to distinguish clearly between the locally audited script and the external npm package, which is outside the Skill’s audit boundary. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (4)

Vague Triggers

Medium
Confidence
92% confidence
Finding
The trigger list includes broad natural-language phrases like "twitter," "tweet," and "tweets from," which can cause the agent to invoke this skill in situations where the user did not clearly request an external X/Twitter lookup. In an agent setting, overly broad activation increases the chance of unintended data transmission to the external Felo API and tool misuse outside the intended scope.

Lp3

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding
The skill documentation describes use of environment variables and outbound network access, but it does not declare any corresponding tool scope such as allowed-tools or permissions. This creates a least-privilege and review gap: a host agent may enable broader capabilities than users or auditors expect, making secret access and external calls harder to govern.

External Transmission

Medium
Category
Data Exfiltration
Content
| `-j, --json` | Output raw JSON |
| `-t, --timeout <seconds>` | Timeout in seconds (default: 30) |

### Option B: Call API with curl

```bash
# Search tweets
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Missing User Warnings

Low
Confidence
84% confidence
Finding
The README states that the skill searches tweets, users, and replies via the Felo X Search API, but it does not explicitly warn that user queries, usernames, tweet IDs, or related inputs may be transmitted to a third-party service. This omission can lead to privacy surprises and unintended disclosure of user-supplied data, especially when combined with automatic agent invocation.

Static analysis

Detected: suspicious.env_credential_access

Environment variable access combined with network send.

Critical
Code
suspicious.env_credential_access
Location
scripts/run_x_search.mjs:250