Back to skill

Security audit

AI生成

Security checks for vulnerabilities and agentic risk

Overview

The skill matches its advertised ad-generation purpose, but it has a real availability risk because user-controlled generation counts are not bounded and cancellation does not stop scheduled work.

Install only if you are comfortable with a Chinese-language ad-generation helper that currently appears to use mock in-memory generation. Before production use, add a strict maximum for generation count, enforce queue and concurrency limits, and fix cancellation so cancelled tasks cannot continue or emit completion events.

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
index.ts:38
Finding

Unbounded Generation Count Enables Resource Exhaustion

Content
View full analysis

Vulnerability Details

File Location: index.ts, lines 38-51, 220-232, and 279
Vulnerability Type: Uncontrolled resource consumption caused by missing input validation
Risk Level: High

Vulnerable Code

ts
async create(task: {
  demandId?: string;
  prompt: string;
  model?: string;
  params?: Record<string, any>;
  count: number;
}): Promise<string> {
  const id = `GEN-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
  const model = task.model || this.api.config?.defaultModel || "flux";

  const genTask: GenerationTask = {
    id,
    demandId: task.demandId,
    prompt: task.prompt,
    model,
    params: task.params || {},
    count: task.count,
    status: "queued",
    createdAt: new Date(),
    updatedAt: new Date(),
  };
ts
// Generate mock results
task.results = [];
for (let i = 0; i < task.count; i++) {
  task.results.push({
    materialId: `MAT-${id}-${i}`,
    prompt: task.prompt,
    model: task.model,
    params: task.params,
    score: Math.random() * 10, // Random score 0-10
    status: "generated"
  });
}
ts
count: { type: "number", help: "生成数量 (默认4)", default: 4 },

Technical Analysis

The externally supplied count value is accepted as a generic number and copied directly into the generation task. No check ensures that it is a finite positive integer or that it remains below a safe maximum.

After a two-second delay, simulateCompletion uses this value as the bound of a synchronous loop. Every iteration allocates a result object and appends it to an in-memory array. An excessively large finite count can therefore monopolize the JavaScript event loop and cause substantial memory allocation.

Although the code reads the maxConcurrent configuration value, it does not implement a queue or enforce concurrency limits. An attacker could consequently create multiple oversized tasks before their timers execute, amplifying resource consumption.

Attack Path

  1. An attacker or ...[truncated 1222 chars]
Remediation
View remediation

Remediation Suggestions

  1. Validate count at the command boundary and again inside create, so internal callers cannot bypass validation.
  2. Require the value to be a finite positive integer:
ts
const MAX_RESULTS_PER_TASK = 100;

if (
  !Number.isFinite(task.count) ||
  !Number.isInteger(task.count) ||
  task.count < 1 ||
  task.count > MAX_RESULTS_PER_TASK
) {
  throw new Error(
    `count must be an integer between 1 and ${MAX_RESULTS_PER_TASK}`
  );
}
  1. Select a conservative maximum based on measured memory and execution costs.
  2. Enforce per-caller rate limits and quotas if caller identity is available.
  3. Implement a real bounded queue that enforces maxConcurrent instead of merely reading the configuration value.
  4. Avoid large synchronous loops. Process bounded batches with cancellation checks and yield control between batches.
  5. Add aggregate limits for queued tasks and generated results to prevent many individually valid requests from exhausting resources.
  6. Add automated tests for zero, negative, fractional, non-finite, and excessively large count values.

T09 · Insecure Skill Coding Practices

Warning
Location
index.ts:73
Finding

Cancelled Tasks Continue Processing and Are Marked Completed

Content
View full analysis

Vulnerability Details

File Location: index.ts, lines 73-89 and 202-239
Vulnerability Type: Improper cancellation and asynchronous state-management flaw
Risk Level: Medium

Vulnerable Code

ts
async cancel(id: string): Promise<boolean> {
  const task = this.tasks.get(id);
  if (!task) {
    throw new Error(`Task not found: ${id}`);
  }

  if (task.status === "generating") {
    task.status = "cancelled";
    task.updatedAt = new Date();
    this.tasks.set(id, task);
    this.api.log(`info`, `Generation task cancelled: ${id}`);
  } else {
    throw new Error(`Cannot cancel task in status: ${task.status}`);
  }

  return true;
}
ts
private async queueTask(id: string): Promise<void> {
  const task = this.tasks.get(id);
  if (!task) return;

  task.status = "generating";
  this.tasks.set(id, task);

  // Simulate generation (would integrate with actual AI models)
  this.api.log(`info`, `Starting generation for task ${id}`);

  // Process with configured concurrency
  const maxConcurrent = this.api.config?.maxConcurrent || 3;
  // In real implementation, would manage a queue

  // For demo, simulate completion after delay
  setTimeout(async () => {
    await this.simulateCompletion(id);
  }, 2000);
}

private async simulateCompletion(id: string): Promise<void> {
  const task = this.tasks.get(id);
  if (!task) return;

  // Generate mock results
  task.results = [];
  for (let i = 0; i < task.count; i++) {
    task.results.push({
      materialId: `MAT-${id}-${i}`,
      prompt: task.prompt,
      model: task.model,
      params: task.params,
      score: Math.random() * 10, // Random score 0-10
      status: "generated"
    });
  }

  task.status = "completed";
  task.updatedAt = new Date();
  this.tasks.set(id, task);

  this.api.log(`info`, `Generation completed for task ${id}: ${task.count} results`);
  this.api.emit("generation.batch_completed", { taskId: id, count: task.count });
}

Technical Analys

...[truncated 2104 chars]

Remediation
View remediation

Remediation Suggestions

  1. Store timeout or job handles for each task and clear the relevant handle during cancellation.
  2. Check task state immediately before starting work and repeatedly during any long-running operation.
  3. Use an explicit cancellation primitive, such as AbortController, when integrating actual AI providers.
  4. Ensure that only valid state transitions are permitted; in particular, prevent cancelled from transitioning to completed.
  5. Do not emit completion events for cancelled jobs.
  6. Wrap delayed asynchronous callbacks with error handling to prevent unhandled promise rejections.
  7. For example:
ts
private timers = new Map<string, ReturnType<typeof setTimeout>>();

private async queueTask(id: string): Promise<void> {
  const task = this.tasks.get(id);
  if (!task) return;

  task.status = "generating";
  task.updatedAt = new Date();

  const timer = setTimeout(() => {
    this.timers.delete(id);
    void this.simulateCompletion(id).catch(error => {
      this.api.log("error", `Generation failed for ${id}: ${String(error)}`);
    });
  }, 2000);

  this.timers.set(id, timer);
}

async cancel(id: string): Promise<boolean> {
  const task = this.tasks.get(id);
  if (!task) throw new Error(`Task not found: ${id}`);
  if (task.status !== "generating") {
    throw new Error(`Cannot cancel task in status: ${task.status}`);
  }

  const timer = this.timers.get(id);
  if (timer) {
    clearTimeout(timer);
    this.timers.delete(id);
  }

  task.status = "cancelled";
  task.updatedAt = new Date();
  return true;
}

private async simulateCompletion(id: string): Promise<void> {
  const task = this.tasks.get(id);
  if (!task || task.status !== "generating") return;

  // Perform bounded work with additional cancellation checks.
}
  1. Add race-condition tests that cancel tasks immediately before callback execution and verify that no results or completion events are produced.
Vulnerability Patterns
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
Findings (6)

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The manifest description and the main skill documentation are written entirely in Chinese, and the skill title/usage guidance indicate a Chinese-language experience without any opt-in or alternative language option. This can violate language/locale policy when users are not given a choice and no region-specific justification is documented.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The user-facing suggestion strings are hardcoded in Chinese, and the command metadata later in the file is also presented in Chinese only. This imposes a specific language on users without offering a locale choice or documenting a justified region-specific constraint.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The command description, subcommand descriptions, argument help text, and returned user-facing messages are written in Chinese only. Under the language/locale policy, forcing one language without opt-in is a natural-language policy issue unless the skill is clearly documented as region-specific.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

The natural-language description is written only in Chinese ("AI生成技能 - 负责广告创意的AI生成处理") and provides no indication that users can choose another language or locale. Under the policy, language constraints should be opt-in or clearly justified as region-specific.

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

json
"license": "MIT",
  "dependencies": {},
  "devDependencies": {
    "@types/node": "^20.0.0",
    "typescript": "^5.0.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 21)May include surrounding context.

json
"dependencies": {},
  "devDependencies": {
    "@types/node": "^20.0.0",
    "typescript": "^5.0.0"
  }
}

Static analysis

No suspicious patterns detected.