Back to skill

Security audit

scrape-creator-profile

Security checks for vulnerabilities and agentic risk

Overview

The skill has a coherent public-profile scraping purpose, but it needs review because it can fetch user-provided URLs, use browser sessions or Apify, and write scraped data with unsafe export handling.

Install only if you intend to scrape public creator profiles and are comfortable with network collection. Avoid using logged-in browser sessions unless necessary, require confirmation before Apify fallback, use a narrowly scoped Apify token, and treat saved JSON or CSV exports as untrusted data until the path and spreadsheet-formula issues are fixed.

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

T09 · Insecure Skill Coding Practices

Error
Location
SKILL.md:64
Finding

Unrestricted Profile URL Fetching Enables Server-Side Request Forgery

Content
View full analysis

Vulnerability Details

File Location: SKILL.md, lines 64–101
Vulnerability Type: Server-Side Request Forgery through unrestricted user-supplied URLs
Risk Level: High

Vulnerable Code

markdown
If the user provides a URL, jump straight to **Step 2**. If they only give a
name or handle, start at **Step 1**.
markdown
## Step 2 — Fetch the Profile Page

### 2a. Try plain web_fetch first

web_fetch(url)

text

Technical Analysis

The Skill directs the Agent to pass a user-provided URL directly to web_fetch without first validating its scheme, hostname, resolved IP address, port, or redirect destination. Although the declared functionality only requires access to supported public creator platforms, the instructions do not enforce the documented platform-domain list.

An attacker could supply a URL pointing to localhost, a private network address, a link-local address, a cloud metadata endpoint, or another internal service. DNS rebinding and redirects could also bypass a hostname-only check if the destination is not revalidated after DNS resolution and on each redirect.

Exploitability depends on the network isolation and filtering implemented by the host's web_fetch or browser tools. The Skill itself provides no defensive control.

Attack Path

  1. An attacker asks the Agent to scrape a purported creator-profile URL.
  2. The supplied URL instead targets an internal resource, such as a loopback address, private network service, or link-local metadata endpoint.
  3. Following the Skill instructions, the Agent jumps directly to Step 2.
  4. The Agent invokes web_fetch(url) without platform or destination validation.
  5. If the host tool permits the request, it accesses the internal resource.
  6. The response may be exposed in the conversation or processed as profile data.
  7. The attacker can repeat the process to enumerate internal hosts, ports, endpoints, or sensitive metada ...[truncated 710 chars]
Remediation
View remediation

Remediation Suggestions

  1. Accept only https URLs.
  2. Enforce an explicit allowlist of supported creator-platform domains and required subdomains.
  3. Reject URLs containing embedded credentials, unexpected ports, malformed hostnames, or non-HTTP schemes.
  4. Resolve the hostname before each request and reject loopback, private, link-local, multicast, reserved, and unspecified IP ranges for both IPv4 and IPv6.
  5. Revalidate the destination after every redirect and limit the number of redirects.
  6. Protect against DNS rebinding by ensuring the actual connection address matches a validated public address.
  7. If the URL is outside the supported allowlist, require explicit user confirmation and route it through a sandboxed fetcher with strict egress controls.
  8. Do not return raw responses from blocked or unexpected destinations.

T09 · Insecure Skill Coding Practices

Warning
Location
references/apify-actors.md:11
Finding

Apify API Token Is Exposed in the Request URL and Process Arguments

Content
View full analysis

Vulnerability Details

File Location: references/apify-actors.md, lines 11–14
Vulnerability Type: Insecure credential transmission and handling
Risk Level: Medium

Vulnerable Code

bash
curl -s -X POST \
  "https://api.apify.com/v2/acts/{ACTOR_ID}/run-sync-get-dataset-items?token=$APIFY_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{INPUT_JSON}'

Technical Analysis

The documented command expands APIFY_API_TOKEN directly into the request URL. Although HTTPS protects the URL in transit, URL query parameters are commonly retained by process listings, shell tracing, command audit logs, HTTP client telemetry, proxies, server access logs, monitoring systems, and debugging output.

While the variable itself is not exported in the repository, following this command pattern converts the secret into a command-line argument visible to other sufficiently privileged local processes. The destination is the expected Apify API, so this is insecure credential handling rather than covert data exfiltration.

Attack Path

  1. A user configures a valid APIFY_API_TOKEN.
  2. The Agent invokes the documented curl fallback command.
  3. The shell expands the token into the URL passed as a process argument.
  4. A local process monitor, shell trace, audit service, proxy, or URL logging system records the full URL.
  5. An attacker with access to that record obtains the token.
  6. The attacker reuses the token against the Apify API until it is revoked or expires.

Impact Assessment

A disclosed token may allow an attacker to use permissions associated with the victim's Apify account. Depending on token scope and account configuration, this could include:

  • Starting actor runs and consuming paid compute units
  • Causing unexpected account charges
  • Reading actor run information or datasets available to the token
  • Enumerating account resources permitted by the credential
  • Exhausting quo ...[truncated 139 chars]
Remediation
View remediation

Remediation Suggestions

  1. Send the token in Apify's supported authorization header rather than a query parameter, for example:

    bash
    curl -sS -X POST \
      "https://api.apify.com/v2/acts/{ACTOR_ID}/run-sync-get-dataset-items" \
      -H "Authorization: Bearer $APIFY_API_TOKEN" \
      -H "Content-Type: application/json" \
      --data-binary '{INPUT_JSON}'
    
  2. Confirm the exact authorization scheme against current Apify documentation.

  3. Disable shell tracing around commands that use credentials.

  4. Avoid printing commands, headers, or environment variables in logs.

  5. Use a narrowly scoped token where supported.

  6. Rotate any token that may already have appeared in process, proxy, or audit logs.

  7. Apply rate, spending, and usage alerts to detect unauthorized actor runs.

T09 · Insecure Skill Coding Practices

Error
Location
scripts/save_profile.py:17
Finding

Unsanitized Profile Fields Permit Output-Directory Escape

Content
View full analysis

Vulnerability Details

File Location: scripts/save_profile.py, lines 17–46
Vulnerability Type: Path traversal and unsafe file overwrite
Risk Level: High

Vulnerable Code

python
def auto_filename(profile: dict) -> str:
    handle = profile.get("handle", "unknown").lstrip("@").lower()
    platform = profile.get("platform", "unknown").lower()
    ts = datetime.now(timezone.utc).strftime("%Y%m%d")
    return f"{handle}_{platform}_{ts}.json"
python
output_path = Path(args.output) if args.output else Path.home() / "creator-profiles" / auto_filename(profile)
output_path = output_path.expanduser().resolve()
output_path.parent.mkdir(parents=True, exist_ok=True)

with open(output_path, "w", encoding="utf-8") as f:
    json.dump(profile, f, indent=2, ensure_ascii=False)

Technical Analysis

The automatic filename includes the profile's handle and platform values without removing path separators, traversal components, control characters, or other filesystem-significant content. These fields may originate from scraped and therefore attacker-controlled profile content.

Calling resolve() only canonicalizes the resulting path; it does not verify that the path remains beneath ~/creator-profiles. A value containing path separators and .. components can therefore cause the resolved destination to escape the intended output directory.

The script then creates parent directories and opens the destination in "w" mode. If a matching file exists, it is truncated and replaced. The attacker does not have completely unconstrained control over the automatic filename because the script appends platform and date components, but they can influence the destination directory and filename sufficiently to write outside the intended storage root. The explicit --output option is intentionally user-controlled; the primary vulnerability is traversal through automatically generated names.

Attack P

...[truncated 1480 chars]

Remediation
View remediation

Remediation Suggestions

  1. Normalize handle and platform to a strict allowlist, such as ASCII letters, digits, underscores, and hyphens.

  2. Replace all path separators and traversal components rather than merely trimming prefixes.

  3. Impose a reasonable maximum filename length.

  4. Build the destination beneath a fixed output root and verify containment after resolution:

    python
    root = (Path.home() / "creator-profiles").resolve()
    destination = (root / safe_filename).resolve()
    if destination.parent != root:
        raise ValueError("Invalid output filename")
    
  5. For nested output support, use destination.is_relative_to(root) and separately validate each path component.

  6. Use exclusive creation mode ("x") by default to prevent silent replacement, or require explicit overwrite confirmation.

  7. Set restrictive file permissions when profile data contains public contact information.

  8. Treat --output as a privileged user choice and document that it can write outside the default directory.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/compare_profiles.py:46
Finding

Untrusted Profile Fields Are Exported as Executable Spreadsheet Formulas

Content
View full analysis

Vulnerability Details

File Location: scripts/compare_profiles.py, lines 46–74
Vulnerability Type: CSV formula injection
Risk Level: Medium

Vulnerable Code

python
def build_rows(profiles: list[dict]) -> tuple[list[str], list[list[str]]]:
    headers = [f[0] for f in COMPARE_FIELDS]
    rows = []
    for p in profiles:
        rows.append([extractor(p) or "" for _, extractor in COMPARE_FIELDS])
    return headers, rows
python
def render_csv(headers: list[str], rows: list[list[str]]) -> str:
    out = io.StringIO()
    w = csv.writer(out)
    w.writerow(headers)
    w.writerows(rows)
    return out.getvalue()

Technical Analysis

Fields such as handle, platform, display name, and website may contain attacker-controlled text scraped from public profiles. These values are passed directly to csv.writer without spreadsheet-formula neutralization.

CSV quoting protects the document structure but does not prevent spreadsheet applications from interpreting a cell as a formula. Values beginning with characters such as =, +, -, or @ may be evaluated when the exported file is opened. Leading tabs, carriage returns, or whitespace can also bypass simplistic prefix checks in some spreadsheet products.

The exact consequences depend on the spreadsheet application and its security settings. Modern applications may warn or block dangerous operations, but external requests and formula execution can still create confidentiality and integrity risks.

Attack Path

  1. An attacker publishes a creator profile containing a formula-like display name, handle, or website value.
  2. The Skill scrapes the malicious value and stores it in the normalized profile object.
  3. A user requests a multi-profile CSV comparison.
  4. build_rows() copies the value without sanitization.
  5. render_csv() writes the value to the CSV document.
  6. The victim opens the exported CSV in a spreadsh ...[truncated 884 chars]
Remediation
View remediation

Remediation Suggestions

  1. Sanitize every string cell before CSV serialization.
  2. Treat cells beginning with =, +, -, or @ as dangerous.
  3. Also account for leading spaces, tabs, carriage returns, and newlines before a formula marker.
  4. Prefix dangerous values with an apostrophe or another spreadsheet-safe neutralization character.
  5. Preserve the original value separately if exact raw data is required.
  6. Document that CSV output contains untrusted public-profile content.
  7. Add unit tests for formula payloads, including values beginning with whitespace and control characters.
  8. For high-assurance exports, provide JSON as the default machine-readable format and require an explicit option for spreadsheet-compatible CSV.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (12)

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

While the finding overstates the absence of scraping, it correctly notes that the skill supports writing scraped profile data to local disk. Silent persistence of collected profile data can create privacy, retention, and operator-awareness risks, especially when users may expect transient summarization rather than storage.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

While the finding overstates the absence of scraping, it correctly notes that the skill supports writing scraped profile data to local disk. Silent persistence of collected profile data can create privacy, retention, and operator-awareness risks, especially when users may expect transient summarization rather than storage.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

While the finding overstates the absence of scraping, it correctly notes that the skill supports writing scraped profile data to local disk. Silent persistence of collected profile data can create privacy, retention, and operator-awareness risks, especially when users may expect transient summarization rather than storage.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The README states that profile data may be fetched via browser mode or sent to a third-party Apify fallback, but it does not warn users that target URLs, handles, and retrieved profile content may be transmitted over the network or to an external service. In a scraping skill, this omission can mislead operators into processing personal or sensitive targets without understanding the privacy, compliance, and data-sharing implications.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
70% confidence
Finding

Without declared permissions the skill's intent is opaque and cannot be validated.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The trigger guidance is broad enough to activate the skill for generic research requests, not just bounded scraping tasks. Over-broad activation increases the chance that the agent will invoke browser/bash/web-fetch capabilities unnecessarily, expanding data collection and tool-use surface beyond user intent.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The 'Use this skill for any request' language creates an overly permissive activation boundary for creator-related lookup, comparison, lead-list building, and monitoring. In context, this is more dangerous because the skill has network, browser, shell, and write capabilities, so broad routing can lead to unnecessary scraping and accumulation of profile data at scale.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

This reference explicitly instructs use of a third-party scraping service and an API token, but provides no warning that profile URLs, handles, and related user-requested targets will be transmitted to Apify. In a skill designed to collect creator data across platforms, that omission creates a real privacy and data-handling risk because operators may unknowingly send user-supplied targets and metadata to an external processor.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
96% confidence
Finding

The documented curl pattern sends input data to an external API endpoint using an authentication token, which is a concrete external data transmission path. In this skill context, the transmitted input may include user-provided profile targets or potentially sensitive research context, so the lack of approval gates or minimization makes the behavior security-relevant rather than merely informational.

Content

Scanner excerpt · references/apify-actors.md (reported line 11)May include surrounding context.

Base API call pattern

bash
curl -s -X POST \
  "https://api.apify.com/v2/acts/{ACTOR_ID}/run-sync-get-dataset-items?token=$APIFY_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{INPUT_JSON}'

External Transmission

Medium
Category
Data Exfiltration
Confidence
90% confidence
Finding

The explicit reference to the Apify API endpoint confirms dependency on an external service for scraping operations, which means data leaves the local trust boundary. While the URL itself is not malicious, in combination with a scraping skill and credentialed access it increases the risk of silent third-party sharing and operational misuse if used without notice or controls.

Content

Scanner excerpt · references/apify-actors.md (reported line 12)May include surrounding context.

bash
curl -s -X POST \
  "https://api.apify.com/v2/acts/{ACTOR_ID}/run-sync-get-dataset-items?token=$APIFY_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{INPUT_JSON}'

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The script persists scraped creator profile data to local storage, which goes beyond transient scraping/extraction and creates a retention surface for potentially sensitive or regulated personal data. Because the output path can be user-specified and the default behavior silently writes to disk, this increases privacy, compliance, and data handling risk if the skill is invoked without clear user consent or retention controls.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
93% confidence
Finding

The skill provides a concrete path to save scraped profile data to disk without requiring a user-facing disclosure or confirmation at the moment of persistence. Even for public data, undisclosed storage can create privacy, compliance, and data-retention concerns, especially if users expect analysis-only behavior.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.