Back to skill

Security audit

Agent News Digest

Security checks for vulnerabilities and agentic risk

Overview

This is a coherent news digest skill that uses web search and external LLM APIs as advertised, with notable but manageable risks around API-key handling, third-party data sharing, and prompt-injection-prone news content.

Install only if you are comfortable sharing search topics, returned article excerpts, and generated summaries with Tavily and the configured LLM provider. Use limited-scope API keys, avoid sensitive topics, update dependencies, and treat generated summaries and links as untrusted until independently checked. Publishers should document all supported providers, remove or gate the startup mock job, and add validation so the model cannot replace source URLs or manipulate rankings unchecked.

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

T09 · Insecure Skill Coding Practices

Warning
Location
src/analyzer.ts:38
Finding
Indirect Prompt Injection Through Untrusted News Content<![CDATA[ ## Vulnerability Details **File Location**: `src/analyzer.ts:38-62` and `src/analyzer.ts:78-87` **Vulnerability Type**: Indirect prompt injection caused by unsafe integration of untrusted web content into LLM prompts **Risk Level**: Medium ### Vulnerable Code ```ts const articlesText = rawArticles.map((a, i) => `[${i + 1}] 제목: ${a.title}\nURL: ${a.url}\n내용: ${a.content.slice(0, 300)}` ).join('\n\n'); const systemPrompt = `당신은 뉴스 요약 전문가입니다. 주어진 뉴스 기사 목록을 분석하여 반드시 아래 JSON 형식으로만 응답하십시오. 다른 텍스트, 설명, 마크다운 코드블록 없이 순수 JSON만 출력하십시오. 응답 형식: [ { "title": "기사 제목", "url": "기사 URL", "summary": "3줄 이내 한국어 요약", "published_date": "날짜 또는 알 수 없음", "importance_score": 1~5 사이 정수 (5가 가장 중요) } ]`; const userMessage = `주제: ${topic}\n\n기사 목록:\n${articlesText}`; try { const raw = await callLLM(systemPrompt, userMessage); const cleaned = raw.replace(/```json|```/g, '').trim(); return JSON.parse(cleaned); } ``` The resulting model-generated summaries are subsequently inserted into another prompt: ```ts const top5 = [...articles].sort((a, b) => b.importance_score - a.importance_score).slice(0, 5); const summaries = top5.map((a, i) => `${i + 1}. ${a.summary}`).join('\n'); const systemPrompt = `당신은 뉴스 브리핑 전문가입니다. 주어진 뉴스 요약들을 바탕으로 5문장 이내의 자연스러운 한국어 브리핑을 작성하십시오. 마크다운 형식으로 작성하되, 헤더(#)는 사용하지 마십시오.`; const userMessage = `주제: ${topic}\n\n주요 뉴스 요약:\n${summaries}`; return await callLLM(systemPrompt, userMessage); ``` ### Technical Analysis Article titles, URLs, and content returned by Tavily are externally controlled web data. The application interpolates these fields directly into an instruction-bearing LLM message without establishing a clear trust boundary or telling the model to treat embedded instructions as untrusted data. An attacker can publish content whose title or first 300 characters contain instructions directed at the model. If Tavily returns that page, the embedded instructions become part of the LLM prompt. Requiring JSON outpu ...[truncated 2549 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. **Explicitly separate instructions from untrusted data** - Place article content inside clearly marked data delimiters. - State that text inside those delimiters is untrusted source material and that any instructions appearing within it must never be followed. - Prefer structured message content or provider-supported structured inputs over free-form concatenation. 2. **Preserve authoritative fields in application code** - Do not allow the model to generate or replace article URLs and titles. - Assign each source article an internal identifier and ask the model to return only that identifier, its summary, and an importance score. - Reconstruct titles and URLs from the original Tavily results after validation. 3. **Apply strict response validation** - Validate LLM output against a runtime schema. - Require an array of the expected length or an explicitly bounded length. - Require known article identifiers. - Require `importance_score` to be an integer between 1 and 5. - Enforce maximum lengths and expected types for every field. - Reject unknown fields, duplicate identifiers, unexpected URLs, and malformed records. 4. **Reduce second-stage injection propagation** - Sanitize and length-limit summaries before using them in the briefing prompt. - In the briefing system prompt, explicitly identify summaries as untrusted data and prohibit following instructions contained in them. - Consider generating the final briefing deterministically from validated summaries rather than making a second LLM request. 5. **Filter suspicious source content** - Detect instruction-like phrases, role markers, prompt delimiters, and attempts to override prior instructions. - Exclude or flag suspicious records rather than silently treating them as normal article content. - Treat filtering as defense in depth, not as the sole protection. 6. **Constrain and monitor output** - Allow only `http` a ...[truncated 347 chars]
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
  • System Prompt LeakageDirect Leakage, Indirect Extraction, Tool-Based Exfiltration
Findings (38)

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding
A skill described as a targeted Korean news digest but implemented only as a generic LLM-calling interface lacks the constraints implied by its description. That makes the context more dangerous, not less, because a seemingly low-risk content tool may actually process arbitrary prompts and transmit them externally.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
A skill described as a targeted Korean news digest but implemented only as a generic LLM-calling interface lacks the constraints implied by its description. That makes the context more dangerous, not less, because a seemingly low-risk content tool may actually process arbitrary prompts and transmit them externally.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
A skill described as a targeted Korean news digest but implemented only as a generic LLM-calling interface lacks the constraints implied by its description. That makes the context more dangerous, not less, because a seemingly low-risk content tool may actually process arbitrary prompts and transmit them externally.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
A skill described as a targeted Korean news digest but implemented only as a generic LLM-calling interface lacks the constraints implied by its description. That makes the context more dangerous, not less, because a seemingly low-risk content tool may actually process arbitrary prompts and transmit them externally.

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding
A skill described as a targeted Korean news digest but implemented only as a generic LLM-calling interface lacks the constraints implied by its description. That makes the context more dangerous, not less, because a seemingly low-risk content tool may actually process arbitrary prompts and transmit them externally.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
A skill described as a targeted Korean news digest but implemented only as a generic LLM-calling interface lacks the constraints implied by its description. That makes the context more dangerous, not less, because a seemingly low-risk content tool may actually process arbitrary prompts and transmit them externally.

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
84% confidence
Finding
The lockfile includes form-data 4.0.5, which is flagged with a high-severity advisory for CRLF injection in multipart field names. Even though this package is only present transitively via SDK dependencies and the lockfile alone does not prove the vulnerable code path is reachable, a news-digest agent commonly performs outbound API calls and may construct multipart/form-data requests through its SDK stack, so retaining a known vulnerable version is a real supply-chain risk.

Credential Access

High
Category
Privilege Escalation
Content
import * as dotenv from 'dotenv';
import * as path from 'path';

// .env 파일 명시적 로드
dotenv.config({ path: path.resolve(__dirname, '../.env') });

console.log('[Debug] ANTHROPIC_API_KEY Loaded:', process.env.ANTHROPIC_API_KEY ? 'Yes' : 'No');
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
import * as dotenv from 'dotenv';
import * as path from 'path';

// .env 파일 명시적 로드
dotenv.config({ path: path.resolve(__dirname, '../.env') });

console.log('[Debug] ANTHROPIC_API_KEY Loaded:', process.env.ANTHROPIC_API_KEY ? 'Yes' : 'No');
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
import * as dotenv from 'dotenv';
import * as path from 'path';

// .env 파일 명시적 로드
dotenv.config({ path: path.resolve(__dirname, '../.env') });

console.log('[Debug] ANTHROPIC_API_KEY Loaded:', process.env.ANTHROPIC_API_KEY ? 'Yes' : 'No');
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
import * as path from 'path';

// .env 파일 명시적 로드
dotenv.config({ path: path.resolve(__dirname, '../.env') });

console.log('[Debug] ANTHROPIC_API_KEY Loaded:', process.env.ANTHROPIC_API_KEY ? 'Yes' : 'No');
console.log('[Debug] TAVILY_API_KEY Loaded:', process.env.TAVILY_API_KEY ? 'Yes' : 'No');
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
import * as path from 'path';

// .env 파일 명시적 로드
dotenv.config({ path: path.resolve(__dirname, '../.env') });

console.log('[Debug] ANTHROPIC_API_KEY Loaded:', process.env.ANTHROPIC_API_KEY ? 'Yes' : 'No');
console.log('[Debug] TAVILY_API_KEY Loaded:', process.env.TAVILY_API_KEY ? 'Yes' : 'No');
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
import * as path from 'path';

// .env 파일 명시적 로드
dotenv.config({ path: path.resolve(__dirname, '../.env') });

console.log('[Debug] ANTHROPIC_API_KEY Loaded:', process.env.ANTHROPIC_API_KEY ? 'Yes' : 'No');
console.log('[Debug] TAVILY_API_KEY Loaded:', process.env.TAVILY_API_KEY ? 'Yes' : 'No');
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Natural-Language Policy Violations

Medium
Confidence
93% confidence
Finding
Natural-language policy checks apply to all file types. The file's user-facing instructions are written in Korean, which can amount to forcing a specific language unless the skill offers language choice or clearly states that it is intended only for a Korean-speaking or region-specific context.

Lp3

Medium
Category
MCP Least Privilege
Confidence
82% confidence
Finding
The skill advertises network-backed news collection and likely relies on environment-provided API keys, but the manifest does not declare any explicit tool scope or permissions. This creates hidden capability risk: operators and users cannot accurately review what external access the skill requires, making unauthorized data egress or unintended network use harder to detect.

Natural-Language Policy Violations

Medium
Confidence
91% confidence
Finding
The feature list explicitly states that the agent produces 'high-quality Korean summaries,' which imposes a language choice in the skill's behavior. Under the policy, forcing a specific language without user opt-in or a clearly documented regional justification is a natural-language policy violation.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
The package description is written as a Korean-only skill description ('키워드 기반 뉴스 수집 및 3줄 요약 에이전트'), which indicates a language-specific behavior without offering any user choice or explaining a justified regional constraint. This matches the policy category for language or locale restrictions expressed in natural language.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The code builds a prompt from article titles, URLs, and content snippets, then sends that data to `callLLM`, which invokes an external provider. While there is provider logging and error logging, there is no warning, comment, or user-facing disclosure here that article data will be sent off-process to an LLM service.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
The natural-language prompts explicitly require summaries and briefings in Korean (`한국어`) and do not provide any opt-in or configuration for other languages. This is a locale/language policy concern because the skill forces a specific language regardless of user preference.

Missing User Warnings

Medium
Confidence
86% confidence
Finding
The function composes a briefing prompt from article summaries and passes it to `callLLM`, which may transmit the data to a remote provider. This file does not include any user-facing warning or explanatory comment near the operation indicating that generated summaries and topic data leave the local environment.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The system prompt for brief generation instructs the model to produce a natural Korean briefing and does not mention any user-selectable language setting. Forcing a single language in prompt text can violate organizational language/locale policy when no opt-in or regional justification is provided.

Context-Inappropriate Capability

Medium
Confidence
79% confidence
Finding
The manifest describes a keyword-based news collection and 3-line summarization agent, which obviously justifies network access for news retrieval. However, explicitly loading a local .env file and inspecting environment-based API credentials introduces a credential-handling capability that is not stated in the skill purpose and goes beyond the user-facing news/summarization function.

Natural-Language Policy Violations

Medium
Confidence
92% confidence
Finding
Multiple comments, warnings, error messages, and status logs are written in Korean, including strings that may be surfaced to users or operators. The file does not indicate that the skill is intentionally Korea-specific or provide any user opt-in for locale, which conflicts with the language/locale policy criteria.

External Transmission

Medium
Category
Data Exfiltration
Content
}

  try {
    const response = await fetch('https://api.tavily.com/search', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
}

  try {
    const response = await fetch('https://api.tavily.com/search', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
Confidence
50% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

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