Back to skill

Security audit

alista

Security checks for vulnerabilities and agentic risk

Overview

The skill is a coherent local bookmark tool, but its social-media fetcher can be tricked into contacting non-social or local network URLs and can write downloaded media outside the intended workspace.

Review before installing. Use this only if you are comfortable sending social-media URLs, captions, tagged users, transcripts/media metadata, and place queries to Apify and Google Places. Until the URL validation issues are fixed, avoid processing untrusted links and avoid --download-images/--extract-frames outside a tightly network-restricted workspace.

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

Error
Location
scripts/fetch-post.ts:110
Finding

Server-Side Request Forgery Through Insufficient Social Platform URL Validation

Content
View full analysis
{ try { const resp = await fetch(url, { 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", Accept: "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8", "Accept-Language": "en-US,en;q=0.9", "Accept-Encoding": "gzip, deflate, br", "Cache-Control": "no-cache", Pragma: "no-cache", "Sec-Fetch-Dest": "document", "Sec-Fetch-Mode": "navigate", "Sec-Fetch-Site": "none", "Sec-Fetch-User": "?1", "Upgrade-Insecure-Requests": "1", }, signal: AbortSignal.timeout(TIMEOUTS.ogTags), redirect: "follow", }); if (!resp.ok) { console.error("[MetadataFetcher] Failed to fetch Instagram page:", resp.status); return null; } const html = await resp.text(); const ogTags = extractOgTags(html); ``` ### Technical Analysis The platform check uses substring matching rather than parsing and validating the URL hostname. Any URL containing the text `instagram.com` or `tiktok.com` can pass, even when its actua ...[truncated 2424 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/fetch-post.ts:43
Finding

Unrestricted Metadata-Supplied Image Downloads Permit SSRF

Content
View full analysis
{ try { const resp = await fetch(imageUrl, { signal: AbortSignal.timeout(15000) }); if (!resp.ok) return false; const buffer = Buffer.from(await resp.arrayBuffer()); await writeFile(outPath, buffer); return true; } catch { return false; } } ``` ```ts // scripts/fetch-post.ts:145-157 if (downloadImagesDir && metadata.imageUrls && metadata.imageUrls.length > 0) { const absDir = resolve(downloadImagesDir); const cwd = process.cwd(); if (!absDir.startsWith(cwd)) { console.error(JSON.stringify({ error: "Download directory must be under the current working directory" })); process.exit(1); } await mkdir(absDir, { recursive: true }); const downloadedPaths: string[] = []; for (let i = 0; i < metadata.imageUrls.length; i++) { const ext = "jpg"; const outPath = join(absDir, `image_${i + 1}.${ext}`); const ok = await downloadImage(metadata.imageUrls[i], outPath); if (ok) downloadedPaths.push(outPath); } ``` ### Technical Analysis Image URLs returned by Apify or extracted from Instagram Open Graph metadata are treated as trusted and passed directly to `fetch()`. Unlike video frame extraction, which calls `isSafeMediaUrl()`, the image downloader does not enforce: - HTTPS. - An approved CDN hostname. - Publicly routable destination addresses. - Redirect destination validation. - Response content type. - Maximum response size. Metadata obtained from a remote page or third-party scraper is untrusted. A malicious social page, manipulated scraper result, or compromised upstream service can therefore provide an image URL targeting localhost or a private service. The unrestrict ...[truncated 1367 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/fetch-post.ts:143
Finding

Output Directory Containment Check Can Be Bypassed by Prefix-Collision Paths

Content
View full analysis
0) { const absDir = resolve(downloadImagesDir); const cwd = process.cwd(); if (!absDir.startsWith(cwd)) { console.error(JSON.stringify({ error: "Download directory must be under the current working directory" })); process.exit(1); } await mkdir(absDir, { recursive: true }); const downloadedPaths: string[] = []; for (let i = 0; i < metadata.imageUrls.length; i++) { const ext = "jpg"; const outPath = join(absDir, `image_${i + 1}.${ext}`); const ok = await downloadImage(metadata.imageUrls[i], outPath); if (ok) downloadedPaths.push(outPath); } result.downloadedImages = downloadedPaths; } // Extract video frames if requested if (extractFramesDir && metadata.videoUrl) { const absDir = resolve(extractFramesDir); const cwd = process.cwd(); if (!absDir.startsWith(cwd)) { console.error(JSON.stringify({ error: "Frames directory must be under the current working directory" })); process.exit(1); } await mkdir(absDir, { recursive: true }); const frames = await extractVideoFrames(metadata.videoUrl, absDir); result.extractedFrames = frames; } ``` ### Technical Analysis The implementation attempts to restrict output directories to the current working directory using: ```ts absDir.startsWith(cwd) ``` String-prefix matching does not establish filesystem containment. For example, when the working directory is `/tmp/app`, the path `/tmp/app-backup` starts with `/tmp/app` but is not inside it. Both image downloads and extracted video frames use the same flawed check. The generated filenames are predictable: ```text image_1.jpg frame_1.jpg ``` `writeFile()` overwrites existing files by defa ...[truncated 1856 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (30)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The skill collects broader social-media metadata such as captions, transcripts, tagged users, and possibly profile/business information beyond the narrowly stated purpose of saving places. This data overcollection can expose personal or third-party information and creates a mismatch between user expectations and actual processing. In a social-media scraping context, that mismatch is security-relevant because unneeded data collection increases privacy and compliance risk.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The skill collects broader social-media metadata such as captions, transcripts, tagged users, and possibly profile/business information beyond the narrowly stated purpose of saving places. This data overcollection can expose personal or third-party information and creates a mismatch between user expectations and actual processing. In a social-media scraping context, that mismatch is security-relevant because unneeded data collection increases privacy and compliance risk.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The skill collects broader social-media metadata such as captions, transcripts, tagged users, and possibly profile/business information beyond the narrowly stated purpose of saving places. This data overcollection can expose personal or third-party information and creates a mismatch between user expectations and actual processing. In a social-media scraping context, that mismatch is security-relevant because unneeded data collection increases privacy and compliance risk.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The skill collects broader social-media metadata such as captions, transcripts, tagged users, and possibly profile/business information beyond the narrowly stated purpose of saving places. This data overcollection can expose personal or third-party information and creates a mismatch between user expectations and actual processing. In a social-media scraping context, that mismatch is security-relevant because unneeded data collection increases privacy and compliance risk.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
91% confidence
Finding

The skill collects broader social-media metadata such as captions, transcripts, tagged users, and possibly profile/business information beyond the narrowly stated purpose of saving places. This data overcollection can expose personal or third-party information and creates a mismatch between user expectations and actual processing. In a social-media scraping context, that mismatch is security-relevant because unneeded data collection increases privacy and compliance risk.

Content

No source excerpt is available for this finding.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 45)May include surrounding context.

md
tsx scripts/fetch-post.ts "<url>"

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 88)May include surrounding context.

md
tsx scripts/fetch-post.ts "<url>"

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The README encourages fetching Instagram/TikTok metadata and optionally downloading images or extracting video frames, while also requiring third-party API services such as Apify and Google Places. Without an explicit privacy warning, users may not realize that post URLs, metadata, media-derived content, and place queries can be transmitted to external providers, creating a meaningful transparency and data-handling risk.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding

The manifest declares environment variables and network access but does not define an explicit tool/permission scope. That creates an overbroad execution model where an agent may use capabilities not clearly bounded by policy, increasing the chance of unintended external calls or secret use. In a skill that processes untrusted social-media URLs and calls third-party APIs, this ambiguity is more dangerous than in a purely local utility.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The manifest describes a skill for saving restaurants, bars, and cafes from TikTok and Instagram videos, but the code explicitly models an additional content type of "event". That event support is not just incidental typing: it is carried through save and update paths, indicating behavior beyond the described skill scope.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The manifest frames the skill as one that saves places, searches saved places, and provides weekend suggestions. Exposing a delete capability materially changes the skill from a save/search assistant into one that can permanently remove stored user data, which is not disclosed in the description.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The deletePlace function permanently deletes rows from the places table, which is a destructive operation. In this file there is no confirmation prompt, logging, print statement, or explanatory comment/docstring warning that the action is irreversible.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
92% confidence
Finding

This outbound request transmits an Instagram profile URL containing the target username to Apify, which is an external service. In this skill, users are saving and analyzing social-media-derived places, so sharing those looked-up accounts with a third party can expose user interests and activity patterns, making the transmission materially privacy-relevant rather than merely incidental network use.

Content

Scanner excerpt · scripts/lib/metadata-fetcher.ts (reported line 47)May include surrounding context.

ts
try {
			const actorId = "apify~instagram-scraper";
			const runUrl = `https://api.apify.com/v2/acts/${actorId}/run-sync-get-dataset-items?token=${this.apifyApiKey}`;

			const resp = await fetch(runUrl, {
				method: "POST",

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The code sends user-derived Instagram usernames and profile/post URLs to Apify, a third-party scraping service, without any indication in this component that users are informed or that data sharing is minimized. This creates a real privacy and compliance risk because saved social media links and identifiers may be disclosed to an external processor unexpectedly, especially given the skill’s purpose of collecting users’ saved places from social platforms.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
93% confidence
Finding

This request sends a user-supplied Instagram post URL to Apify for scraping. Because the URL may reflect a specific creator, venue, or user-curated content of interest, the code leaks user-provided input to an external service without any visible safeguards in this component, creating privacy and data-governance risk.

Content

Scanner excerpt · scripts/lib/metadata-fetcher.ts (reported line 92)May include surrounding context.

ts
private async getInstagramPostFromApify(url: string): Promise<PostMetadata | null> {
		try {
			const actorId = "apify~instagram-scraper";
			const runUrl = `https://api.apify.com/v2/acts/${actorId}/run-sync-get-dataset-items?token=${this.apifyApiKey}`;

			const resp = await fetch(runUrl, {
				method: "POST",

External Transmission

Medium
Category
Data Exfiltration
Confidence
93% confidence
Finding

This call sends a TikTok post URL to Apify and also requests downloadable video media, increasing the amount and sensitivity of third-party processing. In the context of a skill that collects and analyzes social posts for saved venues, transmitting both the source URL and enabling video download deepens privacy exposure and raises legal/compliance concerns around unnecessary data collection.

Content

Scanner excerpt · scripts/lib/metadata-fetcher.ts (reported line 345)May include surrounding context.

ts
private async getTiktokFromApify(url: string): Promise<PostMetadata | null> {
		try {
			const actorId = "clockworks~tiktok-scraper";
			const runUrl = `https://api.apify.com/v2/acts/${actorId}/run-sync-get-dataset-items?token=${this.apifyApiKey}`;

			const resp = await fetch(runUrl, {
				method: "POST",

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 · scripts/lib/place-verifier.ts (reported line 117)May include surrounding context.

ts
// Include location in the text query for better results
		const textQuery = locationHint ? `${query} in ${locationHint}` : query;

		const resp = await fetch("https://places.googleapis.com/v1/places:searchText", {
			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 · scripts/lib/utils/circuit-breaker.ts (reported line 35)May include surrounding context.

ts
* const breaker = new CircuitBreaker({ threshold: 5, resetTimeMs: 60000 });
 *
 * const result = await breaker.execute(async () => {
 *   return await fetch('https://api.example.com/data');
 * });
 *
 * if (result === null && breaker.isOpen()) {

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 · scripts/lib/utils/retry.ts (reported line 120)May include surrounding context.

ts
* const breaker = new CircuitBreaker({ threshold: 5, resetTimeMs: 60000 });
 *
 * const result = await breaker.execute(async () => {
 *   return await fetch('https://api.example.com/data');
 * });
 *
 * if (result === null && breaker.isOpen()) {

Unsafe Defaults

Medium
Category
Tool Misuse
Confidence
75% confidence
Finding

Tool defaults are unsafe or overly permissive (e.g. disabled TLS verification, no authentication, world-writable permissions). Unsafe defaults widen the attack surface.

Content

Scanner excerpt · scripts/save-place.ts (reported line 18)May include surrounding context.

ts
let city = "";
let category: "restaurant" | "bar" | "cafe" | "event" = "restaurant";
let notes = "";
let verify = false;
let sourceUrl = "";

for (let i = 0; i < args.length; i++) {

Description-Behavior Mismatch

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

The manifest description limits the skill's purpose to restaurants, bars, and cafes. However, the documented supported categories explicitly include 'event', which expands the skill's behavior beyond the stated scope.

Content

No source excerpt is available for this finding.

Known Vulnerable Dependency: @ai-sdk/provider-utils==4.0.19 — 1 advisory(ies): CVE-2026-8769 (@ai-sdk/provider-utils has an Uncontrolled Resource Consumption issue)

Low
Category
Supply Chain
Confidence
85% confidence
Finding

The lockfile pins @ai-sdk/provider-utils to version 4.0.19, which the supplied advisory identifies as affected by uncontrolled resource consumption. In an AI-enabled skill, dependency code may process streamed/model responses or schema validation paths, so a crafted or unusually large input could potentially trigger excessive CPU or memory use and degrade availability.

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

json
"format": "biome format --write scripts/"
	},
	"dependencies": {
		"better-sqlite3": "^11.0.0",
		"date-fns": "^4.1.0",
		"date-fns-tz": "^3.2.0",
		"zod": "^3.23.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 14)May include surrounding context.

json
},
	"dependencies": {
		"better-sqlite3": "^11.0.0",
		"date-fns": "^4.1.0",
		"date-fns-tz": "^3.2.0",
		"zod": "^3.23.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": {
		"better-sqlite3": "^11.0.0",
		"date-fns": "^4.1.0",
		"date-fns-tz": "^3.2.0",
		"zod": "^3.23.0"
	},
	"devDependencies": {