Back to skill

Security audit

Agent Trend Radar

Security checks for vulnerabilities and agentic risk

Overview

This skill is a disclosed web-and-LLM trend analyzer, with ordinary integration risks but no evidence of hidden, destructive, or deceptive behavior.

Install only if you are comfortable providing Tavily and LLM provider API keys and sending keyword queries plus retrieved article snippets to those providers. Treat results as advisory because untrusted web content can influence the LLM output; for production use, add input size limits, strict schema validation, provider/data-transfer disclosure, and dependency updates.

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

T09 · Insecure Skill Coding Practices

Warning
Location
src/analyzer.ts:36
Finding

Indirect Prompt Injection Through Untrusted Web Content

Content
View full analysis
`[${i + 1}] ${a.title}\nURL: ${a.url}\n내용: ${a.content}` ).join('\n\n'); const systemPrompt = `트렌드 분석 전문가입니다. 주어진 뉴스 기사들을 분석하여 키워드의 트렌드 신호를 판단하십시오. 반드시 아래 JSON 형식으로만 응답하십시오. 다른 텍스트 없이 순수 JSON만 출력하십시오. 신호 정의: - Rising: 언급량/관심도가 빠르게 증가하는 중 - Peaking: 현재 최고조, 곧 하락 가능성 - Declining: 언급량/관심도가 줄어드는 중 - Insufficient_Data: 판단하기에 데이터가 부족함 응답 형식 (JSON 객체 하나): { "signal": "Rising | Peaking | Declining | Insufficient_Data", "score": 0~100 사이 정수, "reason": "판단 근거를 2문장으로 설명", "evidence": ["근거로 사용한 URL 1", "URL 2"] }`; const userMessage = `키워드: "${keyword}"\n분석 기간: ${timeframe}\n\n기사 목록:\n${articlesText}`; try { const raw = await callLLM(systemPrompt, userMessage); const cleaned = raw.replace(/```json|```/g, '').trim(); const parsed = JSON.parse(cleaned); results.push({ keyword, signal: parsed.signal ?? 'Insufficient_Data', score: typeof parsed.score === 'number' ? parsed.score : 0, reason: parsed.reason ?? '', evidence: Array.isArray(parsed.evidence) ? parsed.evidence : [], }); } ``` ### Technical Analysis Article titles, URLs, and content returned by Tavily are externally controlled data. They are concatenated directly into an LLM user message without explicit boundaries identifying them as untrusted content and without an instruction requiring the model to ignore commands embedded in the articles. An attacker can publish content containing instructions such as requests to disregard the trend-analysis task, return a fabricated classification, or insert attacker-selected evidence. If Tavily indexes and returns that content, the LLM may interpret those instructions as part of the conversation. The JSON response is parsed syntactically but not validated semantically. In ...[truncated 1841 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
src/handler.ts:8
Finding

Incomplete Runtime Validation Enables Job Crashes and API Cost Amplification

Content
View full analysis
5) { return makeError(agentId, jobId, 'keywords는 최대 5개까지 허용됩니다.'); } // 단계 3: 빈 문자열 키워드 필터링 const keywords = input.keywords.map(k => k.trim()).filter(k => k.length > 0); if (keywords.length === 0) { return makeError(agentId, jobId, '유효한 키워드가 없습니다.'); } // 단계 4: 기본값 설정 const timeframe = input.timeframe ?? '7d'; const region = input.region ?? 'global'; ``` ### Technical Analysis The statement `payload as TrendRadarInput` is only a TypeScript compile-time assertion. It does not validate untrusted values at runtime. The handler accesses `input.keywords` before confirming that `payload` is a non-null object. A `null` payload can therefore cause a property-access exception. Although the code verifies that `keywords` is an array, it does not verify that every element is a string before invoking `trim()`. Values such as numbers, objects, or `null` can cause a runtime exception. The handler also does not impose length limits on individual keywords, `timeframe`, or `region`. It does not verify that `timeframe` is one of the declared values (`1d`, `7d`, or `30d`) or that `region` is a supported bounded string. Oversized values are incorporated into Tavily queries and later into LLM prompts. The maximum of five keyword entries limits request multiplication but does not prevent a small number of extremely large strings from consuming network bandwidth, tokens, processing time, or paid API quota. ### Attack Path Crash path: 1. An attacker submits `null` as the payload or supplies an array c ...[truncated 1128 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Note
Location
src/llm/gemini.ts:20
Finding

Gemini API Key Transmitted in a URL Query Parameter

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
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (32)

Tp4

High
Category
MCP Tool Poisoning
Confidence
89% confidence
Finding

If the implementation only contains generic LLM abstraction and lacks the claimed trend detection/classification features, then the skill is materially misrepresented. Misrepresentation is dangerous in this context because it can be used to obtain broader trust, permissions, or deployment approval than a generic LLM wrapper would otherwise receive.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

If the implementation only contains generic LLM abstraction and lacks the claimed trend detection/classification features, then the skill is materially misrepresented. Misrepresentation is dangerous in this context because it can be used to obtain broader trust, permissions, or deployment approval than a generic LLM wrapper would otherwise receive.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding

If the implementation only contains generic LLM abstraction and lacks the claimed trend detection/classification features, then the skill is materially misrepresented. Misrepresentation is dangerous in this context because it can be used to obtain broader trust, permissions, or deployment approval than a generic LLM wrapper would otherwise receive.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

If the implementation only contains generic LLM abstraction and lacks the claimed trend detection/classification features, then the skill is materially misrepresented. Misrepresentation is dangerous in this context because it can be used to obtain broader trust, permissions, or deployment approval than a generic LLM wrapper would otherwise receive.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

If the implementation only contains generic LLM abstraction and lacks the claimed trend detection/classification features, then the skill is materially misrepresented. Misrepresentation is dangerous in this context because it can be used to obtain broader trust, permissions, or deployment approval than a generic LLM wrapper would otherwise receive.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

If the implementation only contains generic LLM abstraction and lacks the claimed trend detection/classification features, then the skill is materially misrepresented. Misrepresentation is dangerous in this context because it can be used to obtain broader trust, permissions, or deployment approval than a generic LLM wrapper would otherwise receive.

Content

No source excerpt is available for this finding.

Known Vulnerable Dependency: form-data==4.0.5 — 1 advisory(ies): CVE-2026-12143 (form-data: CRLF injection in form-data via unescaped multipart field names and f)

High
Category
Supply Chain
Confidence
89% confidence
Finding

This lockfile pins transitive dependency form-data to 4.0.5, which is reported as affected by a high-severity CRLF injection issue when multipart field names are not properly escaped. Even though this file is only a dependency manifest and does not prove the vulnerable code path is exercised, a real vulnerable package version is present and could be exploited if the skill builds multipart requests from untrusted input through libraries that rely on form-data.

Content

No source excerpt is available for this finding.

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 · src/analyzer.ts (reported line 6)May include surrounding context.

ts
import * as dotenv from 'dotenv';
import * as path from 'path';

// .env 직접 로드
dotenv.config({ path: path.resolve(__dirname, '../.env') });

console.log('[Fetcher] API Key Check:', process.env.TAVILY_API_KEY ? 'FOUND' : 'MISSING');

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 · src/fetcher.ts (reported line 5)May include surrounding context.

ts
import * as dotenv from 'dotenv';
import * as path from 'path';

// .env 직접 로드
dotenv.config({ path: path.resolve(__dirname, '../.env') });

console.log('[Fetcher] API Key Check:', process.env.TAVILY_API_KEY ? 'FOUND' : 'MISSING');

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 · src/analyzer.ts (reported line 7)May include surrounding context.

ts
import * as path from 'path';

// .env 직접 로드
dotenv.config({ path: path.resolve(__dirname, '../.env') });

console.log('[Fetcher] API Key Check:', process.env.TAVILY_API_KEY ? 'FOUND' : 'MISSING');

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 · src/fetcher.ts (reported line 6)May include surrounding context.

ts
import * as path from 'path';

// .env 직접 로드
dotenv.config({ path: path.resolve(__dirname, '../.env') });

console.log('[Fetcher] API Key Check:', process.env.TAVILY_API_KEY ? 'FOUND' : 'MISSING');

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The primary skill description is written only in Korean, which imposes a language choice on users without any opt-in or alternative locale guidance. The policy allows language constraints only when users are given a choice or when the locale restriction is clearly documented and justified.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
84% confidence
Finding

The skill metadata declares no explicit tool scope or permissions, yet the associated implementation reportedly uses network access and environment variables. This is dangerous because consumers reviewing only the manifest cannot tell that the skill may exfiltrate data to external services or use sensitive credentials at runtime.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The natural-language description, feature list, and usage context are presented exclusively in Korean, and there is no indication that users may choose another language or that the skill is intentionally limited to a Korean-speaking context. Under the policy, forcing a specific language without opt-in is a reportable natural-language policy violation.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The analyzer sends raw article titles, URLs, and content to an external LLM provider for classification without any indication of consent, minimization, or provider-boundary disclosure in this component. If the article corpus includes proprietary, licensed, personal, or otherwise sensitive text, this can cause unintended third-party data exposure and retention outside the skill's trust boundary.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The prompt explicitly instructs the model to produce the final briefing 'in Korean' regardless of user preference. This is a natural-language locale constraint with no opt-in, choice, or documented region-specific justification in the file.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

This TypeScript file contains multiple natural-language strings in Korean for operational logs and warnings, such as the comments and runtime messages around search start, missing API key, and API errors. The policy explicitly disallows forcing a specific language without user opt-in, and this file does not offer any localization choice or justify a Korean-only locale.

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/fetcher.ts (reported line 47)May include surrounding context.

ts
}

  try {
    const response = await fetch('https://api.tavily.com/search', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',

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 · src/fetcher.ts (reported line 47)May include surrounding context.

ts
}

  try {
    const response = await fetch('https://api.tavily.com/search', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The file contains Korean-only user-facing error messages and comments such as 'keywords는 1개 이상의 문자열 배열이어야 합니다.' and similar strings. This enforces a specific language/locale without offering user opt-in or documenting that the skill is intentionally Korean-only, which matches the language-policy violation category.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

This code constructs a remote API request to Google and includes both the system prompt and user message in the POST body. While there is a console log that a call is happening, it does not disclose that user-provided and system content are being transmitted to an external service, and the file contains no comment or docstring warning about that data transfer.

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 · src/llm/groq.ts (reported line 15)May include surrounding context.

ts
}
    this.client = new OpenAI({
      apiKey: config.apiKey,
      baseURL: 'https://api.groq.com/openai/v1',
    });
    this.model = config.model || 'llama-3.3-70b-versatile';
  }

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
87% confidence
Finding

The package description is written entirely in Korean and does not indicate that the skill is region-specific or that users may interact in another language. Under the language/locale policy, this can be a natural-language constraint without documented opt-in or justification.

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 15)May include surrounding context.

json
"author": "KimCode",
  "license": "ISC",
  "dependencies": {
    "@anthropic-ai/sdk": "^0.33.1",
    "dotenv": "^16.4.7",
    "openai": "^6.27.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
"license": "ISC",
  "dependencies": {
    "@anthropic-ai/sdk": "^0.33.1",
    "dotenv": "^16.4.7",
    "openai": "^6.27.0"
  },
  "devDependencies": {

Static analysis

Detected: suspicious.env_credential_access

Environment variable access combined with network send.

Critical
Code
suspicious.env_credential_access
Location
src/fetcher.ts:8