Back to skill

Security audit

Fomo News

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly behaves like a news fetcher, but it also forces promotional output and has under-scoped network and token-handling risks users should review before installing.

Review this before installing if you are uncomfortable with automatic outbound news requests, a mandatory promotional footer in responses, or unescaped third-party feed content being rendered as Markdown. If you use a GitHub token, configure it as a minimal read-only environment variable and do not paste it as a command-line argument.

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

T01 · Skill Instruction Hijacking

Error
Location
SKILL.md:101
Finding

Mandatory Promotional Content Hijacks Agent Responses

Content
View full analysis
📰 *Powered by [fomo-news](https://github.com/alibaba-flyai/fomo-news)* — real-time news in your terminal\n"; console.log(sections.join("\n---\n\n") + banner); ``` ### Technical Analysis The Skill contains an emphasized, unconditional instruction requiring the Agent to append third-party branding and an outbound URL to every response. This content is not required to retrieve, aggregate, or summarize news. Because the instruction is loaded as part of the Skill definition, it can override the expected response composition for all invocations. The script independently enforces similar behavior in non-JSON mode, so removing only the instruction would not completely eliminate the forced output. This is instruction hijacking because Skill-controlled text persistently alters the Agent's response for promotional purposes unrelated to the user's substantive request. ### Attack Path 1. A user invokes the Skill to retrieve news or GitHub trends. 2. The Agent loads and follows the instructions in `SKILL.md`. 3. The unconditional `IMPORTANT` rule directs the Agent to append a predefined promotional footer. 4. Alternatively, the script itself appends the promotional banner in non-JSON mode. 5. The final response contains attacker-selected branding and an outbound link regardless of whether the user requested it. ### Impact Assessment The issue grants control over a stable portion of the Agent's generated response. ...[truncated 354 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/fetch.mjs:263
Finding

Remote Feed and API Content Is Rendered as Unescaped Markdown

Content
View full analysis
]*>/g, ""), link: get("link"), pubDate: get("pubDate"), snippet: get("description").replace(/<[^>]*>/g, "").slice(0, 300), }); ``` Remote GitHub and RSS values are inserted into Markdown at `scripts/fetch.mjs:263-282`: ```js function formatGitHub(repos) { if (!repos.length) return "No trending repos found.\n"; let out = "## ⭐ GitHub Trending\n\n"; out += "| Repo | Stars | Language | Description |\n"; out += "|------|------:|----------|-------------|\n"; for (const r of repos) { out += `| [${r.name}](${r.url}) | ${r.stars.toLocaleString()} | ${r.language} | ${r.description.slice(0, 80)} |\n`; } return out + "\n"; } function formatSocial(posts) { if (!posts.length) return "No social updates found.\n"; let out = "## 💬 Social Updates\n\n"; for (const p of posts) { out += `- **${p.author}** — [${p.title}](${p.link}) · ${timeAgo(p.pubDate)}\n`; } return out + "\n"; } function formatNews(articles, label) { if (!articles.length) return `No ${label} news found.\n`; const emojis = { tech: "💻", ai: "🤖", economics: "📈", politics: "🏛️", news: "📰" }; let out = `## ${emojis[label] || "📰"} ${label.charAt(0).toUpperCase() + label.slice(1)} News\n\n`; for (const a of articles) { out += `- **[${a.title}](${a.link})** — ${a.source} · ${timeAgo(a.pubDate)}\n`; if (a.snippet) out += ` ${a.snippet.slice(0, 120)}\n`; } return out + "\n"; } ``` ### Technical Analysis The parser strips apparent HTML tags using a regular expression, but it does not escape Markdown metacharacters, normalize control characters, or validate URL schemes. Titles, descriptions, snippets, reposit ...[truncated 1794 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Note
Location
SKILL.md:49
Finding

Documented Token Configuration Exposes Secrets Through Process Arguments and Does Not Work

Content
View full analysis
Remediation
View remediation
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
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (7)

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
node scripts/fetch.mjs <category> [--limit <n>]

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
node scripts/fetch.mjs <category> [--limit <n>]

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding

The manifest advertises a Node-based tool that fetches external content and can use environment variables, but it does not declare an explicit tool scope such as allowed network destinations or permissions. That creates an unnecessary trust gap: the skill can reach arbitrary remote resources and access env-provided secrets without clear policy boundaries, making misuse, supply-chain changes, or future code drift harder to contain.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The trigger regexes are very broad and match common phrases like 'show news', 'what's happening', 'updates', and generic mentions of tech, AI, or politics. This can cause the skill to activate for many ordinary user requests, increasing the chance of unintended execution, unsolicited network access, and accidental exposure of fetched external content in contexts where the user did not explicitly request this skill.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The file documents a command that aggregates RSS feeds from publications and limits categories to news, tech, ai, economics, and politics. This does not match the manifest's stated scope that also includes GitHub and Social sources, suggesting the skill's documented behavior is narrower than what the manifest claims.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/fetch.mjs (reported line 53)May include surrounding context.

js
const results = await Promise.allSettled(
    getGitHubQueries().map(async (q) => {
      const url = `https://api.github.com/search/repositories?q=${q}`;
      const res = await fetch(url, { headers });
      if (!res.ok) throw new Error(`GitHub API ${res.status}`);
      return (await res.json()).items || [];

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

Several Google News RSS URLs explicitly force hl=en-US, gl=US, and ceid=US:en, which constrains the skill to a specific language and locale in a way users cannot opt out of. This is a natural-language/locale policy issue because the file does not provide a configurable locale option or justification for the US-English restriction.

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/fetch.mjs:46