Back to skill

Security audit

X Trends

Security checks for vulnerabilities and agentic risk

Overview

This is a straightforward CLI that fetches public X trend data, with some dependency and output-sanitization risks but no evidence of hidden, persistent, credential-seeking, or destructive behavior.

Reasonable to install if you accept a small CLI risk from fetching and displaying third-party web content. Prefer updating dependencies before publication, adding terminal-output sanitization, and adding request timeout and response-size limits, especially if this will be used in scripts or shared environments.

Vulnerability Patterns
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (2)

T09 · Insecure Skill Coding Practices

Warning
Location
index.js:67
Finding

Terminal Escape-Sequence Injection Through Untrusted Trend Data

Content
View full analysis
{ const rank = t.rank.toString().padStart(2, ' '); const name = t.name.length > 28 ? t.name.substring(0, 27) + '…' : t.name.padEnd(30); const volume = t.volume === 'N/A' ? chalk.gray(t.volume) : chalk.cyan(t.volume); console.log(`${chalk.gray(rank + '.')} ${chalk.white.bold(name)} ${volume.padStart(15)}`); }); ``` ### Technical Analysis The trend name and volume are extracted from an external website and passed to terminal output without removing terminal control characters. Applying Chalk formatting does not neutralize arbitrary ANSI, OSC, or other control sequences already embedded in an untrusted string. Consequently, a compromised or malicious upstream response could place escape sequences inside a trend name or volume. When the default table output is displayed, a compatible terminal may interpret those sequences rather than rendering them as ordinary text. The HTTPS connection limits ordinary network interception, so exploitation generally requires control or compromise of `getdaytrends.com`, manipulation of its trend data source, or another ability to influence the HTML returned by that service. ### Attack Path 1. An attacker obtains the ability to influence trend content returned by the external aggregator or compromises the aggregator. 2. The attacker inserts terminal escape sequences into a trend name or volume. 3. A user runs `x-trends` without JSON mode. 4. The CLI extracts the malicious string and sends it directly to `console.log`. 5. The user's terminal interprets the injected sequence. 6. Depe ...[truncated 908 chars]
Remediation
View remediation
String(value) .replace(/\u001B\][^\u0007]*(?:\u0007|\u001B\\)/g, '') .replace(/\u001B(?:[@-_]|\[[0-?]*[ -/]*[@-~])/g, '') .replace(/[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F-\u009F]/g, ''); const safeName = sanitizeTerminalText(t.name); const safeVolume = sanitizeTerminalText(t.volume); ``` The final implementation should use a well-tested library where possible because terminal escape-sequence syntax is complex. ]]>

T09 · Insecure Skill Coding Practices

Note
Location
index.js:42
Finding

Unbounded HTTP Response Buffering and Missing Request Timeout

Content
View full analysis
{ return new Promise((resolve, reject) => { const req = https.get(targetUrl, { headers: { 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36' } }, (res) => { if (res.statusCode === 404) { reject(new Error(`Country '${countrySlug}' not found.`)); return; } if (res.statusCode !== 200) { reject(new Error(`Failed to fetch trends. Status Code: ${res.statusCode}`)); return; } let data = ''; res.on('data', (chunk) => data += chunk); res.on('end', () => resolve(data)); }); req.on('error', (e) => reject(e)); }); }; ``` ### Technical Analysis The HTTPS client does not configure a request timeout and does not enforce a maximum response size. Every received chunk is concatenated into a single in-memory string before Cheerio parses the completed document. A server that responds slowly, never completes the response, or returns an excessively large body can therefore keep the CLI running indefinitely or force it to consume substantial memory. Parsing the accumulated HTML may further amplify CPU and memory consumption. The target host is fixed by the application, so exploitation generally requires compromise or malicious behavior by the external aggregator, influence over its response, or an abnormal upstream failure. ### Attack Path 1. The external service, or infrastructure controlling its response, accepts the HTTPS request. 2. It either sends data indefinitely, delays completion, or returns an excessively large HTTP 200 response. 3. The CLI continuously appends chunks to the `data` string because no byte limit is enforced. 4. The request remains active because ...[truncated 858 chars]
Remediation
View remediation
{ let data = ''; let received = 0; res.on('data', (chunk) => { received += chunk.length; if (received > MAX_RESPONSE_BYTES) { res.destroy(new Error('Response exceeded the allowed size.')); return; } data += chunk; }); res.on('end', () => resolve(data)); }); req.setTimeout(REQUEST_TIMEOUT_MS, () => { req.destroy(new Error('Request timed out.')); }); req.on('error', reject); ``` Ensure that the promise settles only once and that response and request error events are handled consistently. ]]>
Vulnerability Patterns
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
Findings (5)

Known Vulnerable Dependency: undici==7.19.2 — 16 advisory(ies): CVE-2026-1525 (Undici has an HTTP Request/Response Smuggling issue); CVE-2026-6733 (undici vulnerable to HTTP response queue poisoning via keep-alive socket reuse); CVE-2026-1527 (Undici has CRLF Injection in undici via `upgrade` option) +13 more

High
Category
Supply Chain
Confidence
95% confidence
Finding

The lockfile pins transitive dependency undici to 7.19.2, and the supplied advisory data indicates multiple high-severity issues including request/response smuggling, response queue poisoning, and CRLF injection. Even though this package is transitive via cheerio, a vulnerable HTTP client library can expose consumers to upstream-controlled traffic manipulation, header injection, or cross-request contamination when the skill fetches remote content.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
40% confidence
Finding

Dependencies lack version pinning, allowing potential malicious package updates. Consider pinning versions.

Content

Scanner excerpt · package.json (reported line 14)May include surrounding context.

json
"start": "node index.js"
  },
  "dependencies": {
    "chalk": "^5.3.0",
    "cheerio": "^1.0.0",
    "commander": "^12.0.0",
    "ora": "^8.0.0"

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
40% confidence
Finding

Dependencies lack version pinning, allowing potential malicious package updates. Consider pinning versions.

Content

Scanner excerpt · package.json (reported line 15)May include surrounding context.

json
},
  "dependencies": {
    "chalk": "^5.3.0",
    "cheerio": "^1.0.0",
    "commander": "^12.0.0",
    "ora": "^8.0.0"
  },

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
40% confidence
Finding

Dependencies lack version pinning, allowing potential malicious package updates. Consider pinning versions.

Content

Scanner excerpt · package.json (reported line 16)May include surrounding context.

json
"dependencies": {
    "chalk": "^5.3.0",
    "cheerio": "^1.0.0",
    "commander": "^12.0.0",
    "ora": "^8.0.0"
  },
  "author": "Ani",

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
40% confidence
Finding

Dependencies lack version pinning, allowing potential malicious package updates. Consider pinning versions.

Content

Scanner excerpt · package.json (reported line 17)May include surrounding context.

json
"chalk": "^5.3.0",
    "cheerio": "^1.0.0",
    "commander": "^12.0.0",
    "ora": "^8.0.0"
  },
  "author": "Ani",
  "license": "MIT"

Static analysis

No suspicious patterns detected.