Back to skill

Security audit

Noir Photo Generator

Security checks for vulnerabilities and agentic risk

Overview

This skill is a straightforward film-noir image generator that sends user-provided prompts and a Neta token to an external image API, with some install and credential-handling cautions but no evidence of hidden persistence, local data theft, or destructive behavior.

Install from a trusted ClawHub path when possible, avoid running unpinned npx commands with elevated privileges, and treat prompts, reference UUIDs, generated outputs, and the Neta token as data sent to api.talesofai.com. Prefer a short-lived or low-scope token and rotate it if it was pasted into shared shell history or logs.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (2)

T08 · Insecure Dependencies

Warning
Location
SKILL.md:32
Finding

Unpinned Third-Party Package Execution in Installation Instructions

Content
View full analysis

Vulnerability Details

File Location: SKILL.md:32-34; duplicated in README.md:10-14
Vulnerability Type: Supply-chain risk from unpinned package execution
Risk Level: Medium

Complete vulnerable code snippets:

SKILL.md:32-34

bash
## Install
```bash
npx skills add blammectrappora/noir-photo-generator
text

`README.md:10-14`

```bash
Via ClawHub/OpenClaw:

```bash
npx skills add blammectrappora/noir-photo-generator
text

### Technical Analysis

The documented installation command invokes `npx` with the unversioned `skills` package. If that package is not already installed, `npx` can retrieve it from the configured npm registry and execute its CLI. No exact version, integrity hash, lockfile, or other immutable artifact reference constrains the code that will run.

Consequently, the effective installer can change after this skill has been reviewed. Compromise of the package, its maintainer account, its dependencies, or the configured package registry could cause later installations to execute code different from the reviewed implementation.

This finding does not establish that the current `skills` package is malicious. It identifies an unsafe supply-chain boundary in which mutable third-party code is downloaded and executed.

### Attack Path

1. An attacker compromises the npm package, a maintainer account, a transitive dependency, or the registry resolution path for `skills`.
2. The attacker publishes a malicious release under the package version selected by default.
3. A user follows the documented `npx skills add ...` installation command.
4. `npx` downloads and runs the attacker-controlled package code.
5. That code executes with the privileges of the user running the installation command.

### Impact Assessment

Successful exploitation could provide arbitrary code execution under the installing user's account. Depending on that account's permissions, the malicious ins
...[truncated 325 chars]
Remediation
View remediation

Remediation Suggestions

  • Pin the installer package to a specifically reviewed version, for example by using an exact version rather than an unversioned package name.
  • Verify the selected package source and publisher before recommending it to users.
  • Where supported, enforce package integrity through a lockfile, checksum, signature, or immutable artifact reference.
  • Prefer an official installer that does not dynamically execute mutable registry code.
  • Document the expected package version and update it only after reviewing the new release and its dependency tree.
  • Apply the same corrected installation instructions in both SKILL.md and README.md.
  • Advise users not to run installation commands with administrative privileges unless strictly required.

T09 · Insecure Skill Coding Practices

Note
Location
noirphotogenerator.js:13
Finding

API Token Exposed Through Command-Line Arguments

Content
View full analysis

Vulnerability Details

File Location: noirphotogenerator.js:13-29; documented usage in SKILL.md:18-22 and README.md:20-24,63-69
Vulnerability Type: Sensitive credential exposure through process arguments and shell history
Risk Level: Low

Complete vulnerable code snippet:

noirphotogenerator.js:13-29

javascript
function parseArgs(argv) {
  const args = { size: 'portrait', prompt: null, token: null, ref: null };
  const rest = argv.slice(2);
  for (let i = 0; i < rest.length; i++) {
    const a = rest[i];
    if (a === '--size') {
      args.size = rest[++i];
    } else if (a === '--token') {
      args.token = rest[++i];
    } else if (a === '--ref') {
      args.ref = rest[++i];
    } else if (!a.startsWith('--') && args.prompt === null) {
      args.prompt = a;
    }
  }
  return args;
}

SKILL.md:18-22

bash
Requires a Neta API token (free trial at https://www.neta.art/open/). Pass it via the `--token` flag.

```bash
node <script> "your prompt" --token YOUR_TOKEN
text

`README.md:20-24`

```bash
## Usage

```bash
node noirphotogenerator.js "your description here" --token YOUR_TOKEN
text

### Technical Analysis

The application requires the API token to be supplied as a command-line argument and extracts it directly from `process.argv`. Command-line arguments can be retained in shell history and may be collected by terminal logging, process-monitoring, diagnostic, or automation systems. On operating systems whose process inspection controls permit it, another local process or user may also observe the command line while the generator is running.

The reviewed script sends the token as the `x-token` header only to the documented HTTPS service at `api.talesofai.com`; no covert token exfiltration was identified. The vulnerability concerns local disclosure caused by the credential transport mechanism.

### Attack Path


...[truncated 960 chars]
Remediation
View remediation

Remediation Suggestions

  • Support reading the credential from a protected secret source instead of requiring it in process.argv.
  • Prefer a non-echoing interactive prompt or a secret-manager integration for interactive use.
  • If an environment variable such as NETA_API_TOKEN is supported, warn that environment variables must also be protected from logs, crash reports, and overly broad process access.
  • Optionally accept a path to a credential file and require restrictive file permissions.
  • Retain --token only for backward compatibility, emit a security warning when it is used, and deprecate it in favor of safer input methods.
  • Never print the token in status messages or exception output.
  • Update every usage example in SKILL.md and README.md so users are not instructed to place live credentials directly in shell commands.
  • Recommend rotation or revocation of any token suspected of appearing in shared histories or logs.
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • 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
Findings (8)

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The skill description says it uses the Neta AI API, but the analyzed behavior indicates it actually calls a different backend (api.talesofai.com) and also supports reference-based image inheritance/editing not clearly disclosed in the description. Misrepresenting external data destinations is dangerous because it can trick users into sending prompts, tokens, or reference-image data to an unexpected third party under false pretenses.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
91% confidence
Finding

The README instructs users to install and execute a package via npx skills without pinning an exact version or immutable source. This creates a supply-chain risk: users may fetch and run whatever version is current at install time, including a compromised or typosquatted release, which is especially relevant because npx executes downloaded code.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
83% confidence
Finding

The skill declares Bash as a tool but does not specify any explicit tool scope or permissions, even though the documented behavior requires outbound network access to an external API. This weakens least-privilege controls and can allow broader-than-expected execution capability if the skill is installed or run in an environment that honors scope metadata.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The phrase "Use when someone asks to generate or create film noir photo generator images" is ambiguous and not framed as a specific invocation trigger list. It lacks negative examples or constraints, which could cause the skill to match loosely phrased everyday requests about image creation rather than a clearly bounded noir-specific request.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
90% confidence
Finding

The install instruction uses npx skills add blammectrappora/noir-photo-generator without pinning a specific version. That creates a supply-chain risk because future upstream changes or a compromised package resolution path could cause users to install different or malicious code than expected.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
92% confidence
Finding

The hardcoded remote endpoint shows that the skill transmits data to https://api.talesofai.com, which may not be obvious from the skill name/description referencing Neta AI. That mismatch increases supply-chain and transparency risk because users may believe they are interacting with one service while their data and token are actually sent to another backend.

Content

Scanner excerpt · noirphotogenerator.js (reported line 67)May include surrounding context.

js
console.error(`→ Generating film noir image (${dims.width}×${dims.height})...`);

  const submitRes = await fetch('https://api.talesofai.com/v3/make_image', {
    method: 'POST',
    headers,
    body: JSON.stringify(body),

External Transmission

Medium
Category
Data Exfiltration
Confidence
92% confidence
Finding

The hardcoded remote endpoint shows that the skill transmits data to https://api.talesofai.com, which may not be obvious from the skill name/description referencing Neta AI. That mismatch increases supply-chain and transparency risk because users may believe they are interacting with one service while their data and token are actually sent to another backend.

Content

Scanner excerpt · noirphotogenerator.js (reported line 67)May include surrounding context.

js
console.error(`→ Generating film noir image (${dims.width}×${dims.height})...`);

  const submitRes = await fetch('https://api.talesofai.com/v3/make_image', {
    method: 'POST',
    headers,
    body: JSON.stringify(body),

External Transmission

Medium
Category
Data Exfiltration
Confidence
88% confidence
Finding

The polling request repeatedly sends authenticated requests to the same external service using the provided token. While this is part of normal job-status checking, it continues exposing metadata and credentials to a third party and increases the dependency on that external service's security and availability.

Content

Scanner excerpt · noirphotogenerator.js (reported line 98)May include surrounding context.

js
for (let attempt = 0; attempt < 90; attempt++) {
    await new Promise((r) => setTimeout(r, 2000));

    const pollRes = await fetch(`https://api.talesofai.com/v1/artifact/task/${taskUuid}`, {
      method: 'GET',
      headers,
    });

Static analysis

No suspicious patterns detected.