Back to skill

Security audit

GitHub Trending Monitor

Security checks for vulnerabilities and agentic risk

Overview

The skill has a coherent GitHub trending notification purpose, but it exposes payment and subscription data through unsafe defaults and ships a live-looking payment API key.

Review this carefully before installing or publishing. Replace and rotate the SkillPay key, add authentication and object-level authorization to all subscription and payment routes, verify payment callbacks with the provider, add rate limits, disclose third-party data sharing, escape email content, and commit a reviewed lockfile.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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
Findings (6)

T09 · Insecure Skill Coding Practices

Error
Location
skill.json:15
Finding

Hardcoded SkillPay API Credential Published in Project Files

Content
View full analysis
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Error
Location
src/index.js:190
Finding

Unauthenticated Payment Callback Allows Unpaid Subscription Activation

Content
View full analysis
{ try { const { userId, paymentId, status } = req.body; if (status === 'completed') { const subscription = this.subscriptions.get(userId); if (subscription && subscription.paymentId === paymentId) { subscription.status = 'active'; this.subscriptions.set(userId, subscription); } } res.json({ success: true }); ``` The payment identifier needed to satisfy the comparison is returned by the subscription endpoint: ```js this.subscriptions.set(userId, { channels, preferences: { language: preferences.language || '', since: preferences.since || 'daily', schedule: preferences.schedule || process.env.SCHEDULE || '0 9 * * *' }, status: 'pending', paymentId: paymentRequest.paymentId, createdAt: new Date().toISOString() }); res.json({ success: true, message: 'Subscription created, please complete payment', payment: paymentRequest }); ``` ### Technical Analysis The callback trusts the client-controlled `status`, `userId`, and `paymentId` fields. It does not verify: - A provider-generated signature or message authentication code. - A shared webhook secret. - The callback source. - The payment status directly with SkillPay. - The expected amount and currency. - Replay or duplicate callback identifiers. - Whether the payment was already consumed. Because `/subscribe` returns the payment request, a caller can obtain the matching payment ID and then independently claim that the payment was completed. ### Attack Path 1. Submit `POST /subscribe` with an arbitrary `userId` and attacker-selected notification channels. 2. Read `payment.paymentId` from the response. 3. Without completing payment, submit: ```http ...[truncated 815 chars]
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Error
Location
src/index.js:161
Finding

Missing Object-Level Authorization Exposes and Modifies Other Users' Subscriptions

Content
View full analysis
{ try { const { userId } = req.body; if (!userId) { return res.status(400).json({ error: 'Missing userId' }); } this.subscriptions.delete(userId); res.json({ success: true, message: 'Subscription cancelled' }); } catch (error) { console.error('Unsubscribe endpoint error:', error); res.status(500).json({ error: error.message }); } }); // Get subscription status this.app.get('/subscription/:userId', (req, res) => { const { userId } = req.params; const subscription = this.subscriptions.get(userId); if (!subscription) { return res.status(404).json({ error: 'Subscription not found' }); } res.json({ success: true, subscription }); }); ``` Subscription creation also trusts a caller-supplied identity and replaces any existing entry with the same identifier: ```js const { userId, channels, preferences = {} } = req.body; if (!userId || !channels) { return res.status(400).json({ error: 'Missing required fields: userId, channels' }); } const paymentRequest = await this.payment.createPaymentRequest(userId); this.subscriptions.set(userId, { channels, preferences: { language: preferences.language || '', since: preferences.since || 'daily', schedule: preferences.schedule || process.env.SCHEDULE || '0 9 * * *' }, status: 'pending', paymentId: paymentRequest.paymentId, createdAt: new Date().toISOString() }); ``` ### Technical Analysis No authentication middleware is applied to the subscription endpoints. The application treats the `userId` supplied in the URL or request body as authoritative identity. There is therefore no binding between th ...[truncated 1322 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
src/notifiers/email.js:91
Finding

Unescaped Repository and Request Data Enables HTML Injection in Email Reports

Content
View full analysis

🔥 GitHub Trending - ${timeLabel}

${language && language !== 'all' ? `Language: ${language}` : 'All Languages'}

${new Date().toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' })}

`; if (!repos || repos.length === 0) { html += '

❌ No trending repositories found.

'; } else { repos.slice(0, 10).forEach((repo, index) => { html += `
${index + 1}. ${repo.fullName}
${repo.description || 'No description provided.'}
``` Additional unescaped values are inserted later in the same template: ```js ${repo.language ? `
💻 ${repo.language}
` : ''} ``` ### Technical Analysis The email formatter creates HTML through string interpolation but does not perform contextual encoding. It inserts: - Request-controlled `language`. - GitHub-derived `repo.fullName`. - GitHub-derived `repo.description`. - GitHub-derived `repo.language`. - `repo.url` into an HTML attribute. Repository descriptions and names are externally controlled by GitHub repository owners. The `language` preference is directly controlled through API requests. Inserting those values without HTML escaping allows markup to alter the generated email body. Although many email clients restrict script execution, HTML injection can still produce misleading content, hidden elements, remote image tracking, or phishing-style links. Attribute values require URL validation in addition to ordinary text escaping. ### Attack Path 1. An attacker supplies crafted HTML in the `language` field, or controls repository ...[truncated 812 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
src/index.js:51
Finding

Unauthenticated Endpoints Permit Outbound Request and Storage Amplification

Content
View full analysis
{ res.header('Access-Control-Allow-Origin', '*'); res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, Authorization'); next(); }); ``` ```js // Get trending repositories this.app.get('/trending', async (req, res) => { try { const { language = '', since = 'daily' } = req.query; const repos = await this.scraper.getTrending(language, since); res.json({ success: true, data: repos, count: repos.length, language: language || 'all', since }); } catch (error) { console.error('Trending endpoint error:', error); res.status(500).json({ error: error.message }); } }); ``` Subscription creation also performs an outbound payment-provider request and adds an entry to an unbounded in-memory map: ```js const paymentRequest = await this.payment.createPaymentRequest(userId); this.subscriptions.set(userId, { channels, preferences: { language: preferences.language || '', since: preferences.since || 'daily', schedule: preferences.schedule || process.env.SCHEDULE || '0 9 * * *' }, status: 'pending', paymentId: paymentRequest.paymentId, createdAt: new Date().toISOString() }); ``` ### Technical Analysis The application exposes request-amplifying endpoints without authentication, throttling, caching, quotas, or concurrency limits. Each `/trending` request produces an outbound GitHub page request and may produce a second GitHub API request when scraping fails or returns no repositories. Each `/subscribe` request calls the payment provider and can insert an attacker-selected key into the subscription map. Wildcar ...[truncated 1104 chars]
Remediation
View remediation

T08 · Insecure Dependencies

Note
Location
package.json:23
Finding

Unpinned Dependencies and Missing Lockfile Make Builds Non-Reproducible

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
Findings (38)

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · PROJECT_SUMMARY.md (reported line 40)May include surrounding context.

├── skill.json # Clawhub configuration ├── SKILL.md # Skill documentation ├── README.md # Project README ├── .env # Environment variables ├── .gitignore # Git ignore └── test.js # Test script

text

Intent-Code Divergence

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The README includes what appears to be a real SkillPay API key rather than a placeholder example. Publishing live credentials in documentation can allow unauthorized third parties to use the service, incur charges, access account data, or pivot into related systems if the key remains valid.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

This markdown file describes Telegram, Discord, Email notifications and subscription management, and later shows a subscription example containing a userId and chatId, but it does not warn users that these identifiers and notification content may be transmitted to third-party services. For a markdown skill description, external data-sharing behavior that could affect privacy should be disclosed explicitly.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% 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 · PROJECT_SUMMARY.md (reported line 108)May include surrounding context.

Fetch Trending Repos

bash
curl "http://localhost:3000/trending?language=javascript&since=daily"

Subscribe to Daily Reports

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
85% confidence
Finding

The markdown documents POST /notify and POST /subscribe request bodies containing Telegram chat IDs and email addresses, and it describes scheduled outbound notifications. There is no user-facing warning about transmitting/storing these identifiers or about the privacy impact of sending data to Telegram, Discord, and email services.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The configuration section lists multiple sensitive credentials and connection settings without warning users to keep them secret, and in context it also includes an apparently real API key example. This increases the likelihood that users will paste real secrets into files, commit them to source control, or otherwise expose notification and email infrastructure credentials.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

This markdown file documents POST /notify and POST /subscribe requests that send userId plus notification-channel data such as Telegram chat IDs, but it does not warn users that their data will be transmitted to external messaging or email services. Because markdown files should disclose behaviors affecting privacy or user data, the omission is a meaningful safety gap.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The skill requires or supports sensitive credentials including an API key, bot token, webhook URL, and SMTP credentials, but the markdown provides no caution about storing, exposing, or protecting these secrets. For a skill description, this omits an important warning about privacy and system integrity implications.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% 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 · START_HERE.txt (reported line 96)May include surrounding context.

text
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

  # Fetch trending JavaScript repos
  curl "http://localhost:3000/trending?language=javascript&since=daily"

  # Subscribe to daily reports
  curl -X POST http://localhost:3000/subscribe \

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
84% confidence
Finding

This manifest describes the skill generically as providing "Daily monitoring of GitHub trending repositories with multi-channel notifications" but does not specify how or when it should be invoked, nor any limiting trigger phrases or exclusion conditions. In a manifest file, this kind of broad description can contribute to ambiguous activation behavior because the trigger scope is not clearly bounded.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

The code initializes a payment system and later creates payment requests, verifies payments, handles payment callbacks, and logs billable usage. With no manifest available and only code documentation identifying the app as a GitHub trending monitor, integrated payment processing is an additional business capability not inherently required to fetch or notify about trending repositories.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The GET /subscription/:userId endpoint returns the full stored subscription object for any supplied userId with no authentication or authorization checks. Because the object includes channel configuration and payment-related metadata, an attacker can enumerate or guess user IDs and retrieve other users' subscription details.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

This endpoint exposes stored subscription data without any access control, allowing any caller to query another user's subscription status and associated delivery settings. In context, that can leak email targets, Telegram chat IDs, Discord usage, schedule preferences, and internal payment linkage information.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
82% confidence
Finding

The scheduler automatically fetches trending data and sends notifications to Telegram, Discord, or email based on stored subscription settings. Although subscription creation mentions payment completion, this file does not provide any explicit user-facing warning or confirmation that ongoing automated outbound notifications will continue on a schedule.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% 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 · src/payment.js (reported line 9)May include surrounding context.

js
class SkillPayment {
  constructor(apiKey) {
    this.apiKey = apiKey;
    this.baseURL = 'https://api.skillpay.me/v1';
    this.pricePerCall = 0.001; // USDT
  }

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The payment description sent to the processor identifies the charge as "GitHub Trending Monitor - API Call" while the module is documented as "SkillPay Payment Integration." Mislabeling payment purposes can mislead users, complicate dispute resolution, and indicate reused or mismatched billing logic that may result in deceptive or unauthorized-looking charges.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The logUsage function transmits userId, action, timestamp, and amount to a remote analytics endpoint without any visible consent, minimization, or disclosure controls in this code. This creates privacy and compliance risk because user activity data is exported to a third party and could be collected without the user's knowledge or a clear lawful basis.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% 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 · src/scrapers/github.js (reported line 133)May include surrounding context.

js
headers['Authorization'] = `token ${this.githubToken}`;
      }

      const response = await axios.get('https://api.github.com/search/repositories', {
        params: { q: query, sort: 'stars', order: 'desc', per_page: 25 },
        headers
      });

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
93% confidence
Finding

The phrase "Full English documentation" indicates an English-only documentation constraint, and the later section reiterates that all documentation is in English. This is a natural-language locale policy issue because the file presents a fixed language choice without user opt-in or a documented regional/compliance justification.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
97% confidence
Finding

The statement "All documentation is in English" explicitly fixes the skill's documentation language and lists all materials as English-only. Because no alternative language option, opt-in, or justification is provided, this constitutes a natural-language language-policy concern under the audit criteria.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
92% confidence
Finding

The phrase "Full English documentation" indicates the skill materials are fixed to English, and later text reinforces that all code comments and docs are in English. This can violate language or locale policy when no user choice, opt-in, or justification for the language restriction is provided.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

The statement "All code in English - Comments, docs, everything!" is an explicit English-only language constraint in natural-language content. Because the file does not provide an opt-in choice or a documented justification, it matches the language-policy violation category.

Content

No source excerpt is available for this finding.

Vague Triggers

Low
Category
Not specified by scanner
Confidence
83% confidence
Finding

This plain-text file presents "Ready? Run: npm install && npm start" as a generic call to action without clarifying context, prerequisites, or when a user should avoid running it. In a start-here document, that broad imperative can encourage unintended execution because it does not specify environment, trust boundaries, or exclusions.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
94% confidence
Finding

The manifest uses a caret range for axios, which allows automatic installation of newer minor/patch releases rather than a single audited version. This increases supply-chain risk and makes builds non-reproducible, especially for a network-facing package with a history of advisories.

Content

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

json
"author": "zhdryanchang",
  "license": "MIT",
  "dependencies": {
    "axios": "^1.6.0",
    "cheerio": "^1.0.0-rc.12",
    "node-cron": "^3.0.3",
    "telegraf": "^4.15.0",

Unverifiable Dependency: axios has 16 known advisory(ies) (CVE-2026-44494 (axios Vulnerable to Full Man-in-the-Middle via Prototype Pollution Gadget in `co); CVE-2026-44495 (axios Vulnerable to Credential Theft and Response Hijacking via Prototype Pollut); CVE-2025-62718 (Axios has a NO_PROXY Hostname Normalization Bypass that Leads to SSRF) +13 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
78% confidence
Finding

axios has a known advisory history, and because the manifest does not pin an exact version, it is not possible to verify from this file whether deployed installs are affected. In a skill that fetches external content, a vulnerable HTTP client could increase exposure to SSRF, request smuggling, or other network-centric issues depending on the specific resolved version.

Content

No source excerpt is available for this finding.