Back to skill

Security audit

Apify Ultimate Scraper

Security checks for vulnerabilities and agentic risk

Overview

This Apify scraper skill is mostly coherent, but it enables broad contact/follower scraping and exports untrusted scraped data with insufficient privacy and file-safety guardrails.

Install only if you are comfortable giving the skill an Apify token and using it for public-data scraping through Apify. Use it with clearly lawful, consent-aware scraping goals; be especially careful with contact, email, follower, and audience datasets. Prefer JSON or quick answers for untrusted data, and treat CSV exports as potentially unsafe until reviewed. Save outputs only to fresh, ordinary filenames in the current project directory.

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

Warning
Location
reference/scripts/run_actor.js:56
Finding

Output Path Validation Permits Arbitrary File Overwrite Through Symbolic Links

Content
View full analysis
0) { // ... writeFileSync(outputPath, csvLines.join('\n')); } else { writeFileSync(outputPath, ''); } } ``` ### Technical Analysis The validation uses `resolve()` and a string-prefix comparison to determine whether the supplied path is under the current working directory. This only performs lexical path normalization. It does not resolve symbolic links or verify the identity of the final filesystem object. Consequently, a path such as `./result.json` passes validation even when `result.json` is a symbolic link whose target is outside the working directory. Node.js `writeFileSync()` follows symbolic links by default and truncates the linked target before writing the downloaded Actor dataset. This behavior contradicts the security statement in `SKILL.md` that outputs are written only under the current working directory. Exploitation requires an attacker, another local process, or a prior operation to create or replace a writable output path with a symbolic link. ### Attack Path 1. The attacker gains the ability to create a symbolic link in the directory from ...[truncated 1650 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
reference/scripts/run_actor.js:249
Finding

CSV Export Does Not Neutralize Spreadsheet Formulas

Content
View full analysis
0) { const fieldnames = Object.keys(data[0]); const csvLines = [fieldnames.join(',')]; for (const row of data) { const values = fieldnames.map((key) => { let value = row[key]; // Truncate long text fields if (typeof value === 'string' && value.length > 200) { value = value.slice(0, 200) + '...'; } else if (Array.isArray(value) || (typeof value === 'object' && value !== null)) { value = JSON.stringify(value) || ''; } // CSV escape: wrap in quotes if contains comma, quote, or newline if (value === null || value === undefined) { return ''; } const strValue = String(value); if (strValue.includes(',') || strValue.includes('"') || strValue.includes('\n')) { return `"${strValue.replace(/"/g, '""')}"`; } return strValue; }); csvLines.push(values.join(',')); } ``` ### Technical Analysis The exporter performs syntactic CSV escaping for commas, quotes, and newlines, but it does not neutralize values interpreted as formulas by spreadsheet applications. Dataset values beginning with characters such as `=`, `+`, `-`, or `@` are written directly into CSV cells. Field names are also concatenated into the header without either CSV escaping or formula neutralization. Quoting a dangerous value is not a sufficient defense because common spreadsheet applications may still evaluate quoted CSV cells as formulas after parsing. Since the dataset originates from web scraping and potentially third-party Actors, its fields must be treated as untrusted. ### Attack Path 1. An attacker publishes content on a page or ...[truncated 1572 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (9)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding

The skill requires sensitive capabilities (APIFY_TOKEN, network access, and executable binaries) but does not declare an explicit tool scope such as permissions or allowed-tools. That omission weakens containment and reviewability, making it easier for the skill to be invoked with broader-than-necessary authority and harder for a host to enforce least privilege.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The description is broad enough to match generic requests for scraping, lead generation, audience analysis, or data extraction across many platforms. This increases the chance of over-triggering, causing the agent to engage high-risk scraping and outbound data workflows even when the user's request is ambiguous or a safer, narrower skill would be more appropriate.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The skill explicitly promotes lead generation, audience analysis, follower scraping, and email/contact extraction from public platforms without meaningful warnings about privacy, consent, or platform terms. Even when data is publicly accessible, aggregating and exporting it at scale can create privacy harms, facilitate profiling, and expose the operator to compliance and platform-policy violations.

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 · SKILL.md (reported line 251)May include surrounding context.

md
async function startActor(token, actorId, parsedInput) {
    // Convert "author/actor" format to "author~actor" for API compatibility
    const apiActorId = actorId.replace('/', '~');
    const url = `https://api.apify.com/v2/acts/${apiActorId}/runs`;

    const response = await fetch(url, {
        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 · reference/scripts/run_actor.js (reported line 155)May include surrounding context.

js
async function startActor(token, actorId, parsedInput) {
    // Convert "author/actor" format to "author~actor" for API compatibility
    const apiActorId = actorId.replace('/', '~');
    const url = `https://api.apify.com/v2/acts/${apiActorId}/runs`;

    const response = await fetch(url, {
        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 · reference/scripts/run_actor.js (reported line 187)May include surrounding context.

js
async function startActor(token, actorId, parsedInput) {
    // Convert "author/actor" format to "author~actor" for API compatibility
    const apiActorId = actorId.replace('/', '~');
    const url = `https://api.apify.com/v2/acts/${apiActorId}/runs`;

    const response = await fetch(url, {
        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 · reference/scripts/run_actor.js (reported line 226)May include surrounding context.

js
async function startActor(token, actorId, parsedInput) {
    // Convert "author/actor" format to "author~actor" for API compatibility
    const apiActorId = actorId.replace('/', '~');
    const url = `https://api.apify.com/v2/acts/${apiActorId}/runs`;

    const response = await fetch(url, {
        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 · reference/scripts/run_actor.js (reported line 291)May include surrounding context.

js
async function startActor(token, actorId, parsedInput) {
    // Convert "author/actor" format to "author~actor" for API compatibility
    const apiActorId = actorId.replace('/', '~');
    const url = `https://api.apify.com/v2/acts/${apiActorId}/runs`;

    const response = await fetch(url, {
        method: 'POST',

Context-Inappropriate Capability

Low
Category
Not specified by scanner
Confidence
81% confidence
Finding

The manifest describes a universal web scraper for extracting platform data, but does not mention credential or environment access. This file requires reading a secret from process.env to operate, which is a capability beyond pure scraping behavior and is not explicitly declared in the stated purpose.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.