Back to skill

Security audit

News Impact Scale

Security checks for vulnerabilities and agentic risk

Overview

The skill has a coherent news-analysis purpose, but its unrestricted URL fetching can reach unintended internal or private network services.

Install only if you are comfortable with the skill making outbound requests and storing analysis artifacts locally. Use it only with trusted public news URLs, avoid intranet, localhost, cloud metadata, or private-service URLs, and review or minimize `context.json` before use. A safer version should block private-network destinations, cap response size, enforce redirect limits, and make the broad trigger and retention behavior clearer.

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

Error
Location
lib/fetcher.js:8
Finding

Arbitrary URL Fetching Enables Server-Side Request Forgery

Content
View full analysis

Vulnerability Details

File Location: lib/fetcher.js:8-27 (user-controlled source: analyze.js:98-100, 137-141)
Vulnerability Type: Server-Side Request Forgery (SSRF)
Risk Level: High

Vulnerable Code

js
function fetchUrl(targetUrl) {
  return new Promise((resolve, reject) => {
    let redirected = false;
    const lib = targetUrl.startsWith('https') ? https : http;
    const req = lib.get(targetUrl, {
      headers: {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36',
        'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
        'Accept-Language': 'en-US,en;q=0.5',
        'Connection': 'keep-alive',
      }
    }, res => {
      // Follow up to 3 redirects
      if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
        if (redirected) { reject(new Error('Too many redirects')); return; }
        redirected = true;
        const next = new URL(res.headers.location, targetUrl).toString();
        fetchUrl(next).then(resolve).catch(reject);
        return;
      }

The caller passes the command-line argument directly into this function:

js
async function stage1(url) {
  process.stdout.write('🔍 Fetching article...\n');
  const raw=await fetchUrl(url);
js
const[,,cmd,...args]=process.argv;
if(!cmd){console.error('Usage: node analyze.js &lt;url&gt;\n       node analyze.js --final');process.exit(1);}
let out;
if(cmd==='--final') out=await stage3(args[0]?JSON.parse(args[0]):undefined);
else out=await stage1(cmd);

Technical Analysis

The Skill performs an outbound request to a fully user-controlled URL without validating its scheme, destination hostname, resolved IP address, or network range. There is no protection against loopback, private, link-local, reserved, or cloud metadata addresses.

Red ...[truncated 1865 chars]

Remediation
View remediation

Remediation Suggestions

  1. Parse every input with new URL() and reject malformed URLs.
  2. Allow only the exact http: and https: schemes.
  3. Resolve the hostname before connecting and reject all loopback, private, link-local, multicast, unspecified, reserved, and documentation ranges for IPv4 and IPv6.
  4. Explicitly block cloud metadata destinations, including link-local metadata addresses and environment-specific metadata hostnames.
  5. Revalidate the scheme, hostname, and resolved addresses after every redirect.
  6. Protect against DNS rebinding by ensuring the validated address is the address used for the connection.
  7. Prefer a domain allowlist when the intended use is limited to known news sources.
  8. Run the fetch component in a network sandbox that cannot reach internal services or metadata endpoints.
  9. Record security-safe destination audit logs without exposing credentials or sensitive query parameters.

T09 · Insecure Skill Coding Practices

Warning
Location
lib/fetcher.js:8
Finding

Unbounded Response Buffering and Broken Redirect Limit Enable Denial of Service

Content
View full analysis

Vulnerability Details

File Location: lib/fetcher.js:8-37
Vulnerability Type: Resource Exhaustion and Uncontrolled Redirect Recursion
Risk Level: Medium

Vulnerable Code

js
function fetchUrl(targetUrl) {
  return new Promise((resolve, reject) => {
    let redirected = false;
    const lib = targetUrl.startsWith('https') ? https : http;
    const req = lib.get(targetUrl, {
      headers: {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36',
        'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
        'Accept-Language': 'en-US,en;q=0.5',
        'Connection': 'keep-alive',
      }
    }, res => {
      // Follow up to 3 redirects
      if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
        if (redirected) { reject(new Error('Too many redirects')); return; }
        redirected = true;
        const next = new URL(res.headers.location, targetUrl).toString();
        fetchUrl(next).then(resolve).catch(reject);
        return;
      }
      if (res.statusCode !== 200) {
        reject(new Error(`HTTP ${res.statusCode}`));
        return;
      }
      const chunks = [];
      res.on('data', c => chunks.push(c));
      res.on('end', () => resolve(Buffer.concat(chunks).toString('utf8')));
    });
    req.on('error', reject);
    req.setTimeout(20000, () => { req.destroy(); reject(new Error('Request timeout')); });
  });
}

Technical Analysis

The redirect guard is local to each fetchUrl() invocation. A redirect recursively invokes fetchUrl(next), which initializes a new redirected = false. The state is therefore never preserved across the redirect chain, and the implementation does not enforce its claimed redirect limit.

In addition, every response chunk is retained in memory until the response ends. The im ...[truncated 1614 chars]

Remediation
View remediation

Remediation Suggestions

  1. Pass an explicit redirect counter through calls, for example fetchUrl(url, redirectsRemaining), and reject requests when the hard limit reaches zero.
  2. Track visited normalized URLs to detect redirect cycles.
  3. Drain or destroy the previous response before following a redirect.
  4. Enforce a strict maximum response size while streaming; immediately destroy the request when the limit is exceeded.
  5. Validate Content-Length when present, while retaining the streaming limit because that header is untrusted and may be absent or inaccurate.
  6. Restrict accepted response types to expected article formats such as text/html and optionally text/plain.
  7. Apply one absolute deadline to the entire fetch operation, including DNS resolution, redirects, and body download.
  8. Configure connection, header, inactivity, and total-operation timeouts separately.
  9. Add process-level memory and network limits as defense in depth.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (7)

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The skill explicitly states it tailors results using stored location, interests, and travel plans, and it also fetches articles and performs web searches, but it does not present a clear upfront warning or consent mechanism. This creates a privacy and transparency risk because users may not realize the skill is combining sensitive stored context with external requests and derived analysis.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The activation trigger analyze this <url> is overly broad and can collide with ordinary user language, causing the skill to activate in contexts the user did not clearly intend. Because this skill then fetches external content and personalizes output using stored location, interests, and travel plans, accidental activation can lead to unintended network access and use of personal context.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

The skill reads a local context.json containing personal location and interests and uses it to tailor relevance scoring, but there is no disclosure or consent mechanism in this file. Even though the file is local, silently consuming profile data increases privacy risk because users may not realize personal context is being processed to influence outputs.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
76% confidence
Finding

The skill performs a network fetch of a user-supplied URL via fetchUrl(url). Although there is a progress message, it does not explicitly disclose the privacy-relevant behavior that the provided URL and request metadata will be sent to a remote host.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
91% confidence
Finding

The skill persists stage1_output.json locally without notifying the user, and that file can contain fetched article details, inferred classifications, benchmark queries, and personalized relevance derived from local context. Silent persistence creates privacy and data retention risk because sensitive or behavioral information may remain on disk longer than expected.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
76% confidence
Finding

This JSON content is organized under a fixed location key of "China", which can reflect a locale-specific framing without any surrounding documentation in this file indicating that the skill is region-specific or that users can choose a locale. Under the policy rule for natural-language violations, fixed locale constraints should be documented or optional to avoid imposing an unstated regional perspective.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
94% confidence
Finding

The request headers hard-code Accept-Language: en-US,en;q=0.5, which imposes a specific language/locale preference on all fetches. This is a natural-language policy concern because the file does not offer user opt-in or explain why English localization is required.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.