Back to skill

Security audit

Cashclaw Invoicer

Security checks for vulnerabilities and agentic risk

Overview

The skill is a mostly coherent Stripe invoicing helper, but it asks for powerful payment authority and includes unreviewed installation plus immediate refund capability that should be reviewed before use.

Review before installing. Use a restricted Stripe key, avoid storing the key in ~/.cashclaw/config.json unless file permissions are locked down, audit or pin the npm packages before installation, and require explicit human approval before refunds or subscription changes.

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:10
Finding

Unpinned npm Dependencies Permit Unreviewed Supply-Chain Changes

Content
View full analysis

Vulnerability Details

File Location: SKILL.md:10-35
Vulnerability Type: Unpinned third-party dependencies
Risk Level: Medium

Vulnerable Code

yaml
metadata:
  {
    "openclaw":
      {
        "emoji": "\U0001F4B3",
        "requires": { "bins": ["node"], "env": ["STRIPE_SECRET_KEY"] },
        "install":
          [
            {
              "id": "npm",
              "kind": "node",
              "package": "cashclaw",
              "bins": ["cashclaw"],
              "label": "Install CashClaw via npm"
            }
          ]
      }
  }
bash
npm install stripe

Technical Analysis

Both documented installation paths resolve npm packages without exact versions or a committed lockfile. The OpenClaw metadata installs the separate cashclaw package, while the prerequisites instruct users to install the latest version of stripe.

Consequently, the code executed or imported by a future installation can differ from the components present at audit time. npm packages may also define lifecycle scripts that execute during installation. The implementation of the external cashclaw package is not included in this project and could not be reviewed as part of this audit.

This is an insecure dependency-management practice rather than evidence that either current package is malicious.

Attack Path

  1. An attacker compromises the npm account, release process, or upstream repository of a referenced package.
  2. The attacker publishes a malicious version under the legitimate package name.
  3. A user or agent follows the installation metadata or runs npm install stripe.
  4. npm resolves the newly published, unreviewed version because no exact version or lockfile constrains dependency resolution.
  5. Malicious lifecycle or runtime code executes with the privileges of the installing or invoking user.
  6. If Stripe credentials are present in the process envi ...[truncated 631 chars]
Remediation
View remediation

Remediation Suggestions

  1. Pin every direct dependency to an exact, reviewed version rather than a version range or implicit latest release.
  2. Add and commit a package manifest and lockfile containing npm integrity hashes.
  3. Use npm ci in automated installation paths so dependency resolution strictly follows the reviewed lockfile.
  4. Remove the cashclaw package installation declaration if it is not required by this Skill.
  5. If cashclaw is required, independently audit its source, transitive dependencies, and lifecycle scripts before pinning it.
  6. Consider installing with lifecycle scripts disabled where compatible, then explicitly run only reviewed build steps.
  7. Use a restricted Stripe key with only the API permissions required by this Skill, and avoid exposing the key during package installation.
  8. Add dependency scanning and controlled update review to the release process.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/stripe-ops.js:256
Finding

Failed Invoice Reminders Are Recorded as Successfully Sent

Content
View full analysis

Vulnerability Details

File Location: scripts/stripe-ops.js:256-272
Vulnerability Type: Incorrect security- and business-event logging
Risk Level: Medium

Vulnerable Code

javascript
// Stripe does not have a native "send reminder" endpoint, so we re-send the invoice
try {
  await stripe.invoices.sendInvoice(invoiceId);
  console.log("  Reminder sent successfully (invoice re-sent).\n");
} catch (err) {
  // If invoice cannot be re-sent (already sent recently), log it
  console.log(`  Could not re-send invoice: ${err.message}`);
  console.log("  Consider sending a manual reminder email.\n");
}

logEvent({
  event: "reminder_sent",
  invoice_id: invoiceId,
  template,
  amount: invoice.amount_due,
  currency: invoice.currency,
});

Technical Analysis

The reminder_sent event is written after the try/catch block regardless of whether stripe.invoices.sendInvoice() succeeds. The exception is suppressed, the command continues normally, and the ledger receives a success event even when Stripe rejected or failed to process the operation.

This violates the documented requirement to track reminder events accurately. Any operator or downstream process that treats the append-only ledger as authoritative cannot distinguish a successfully delivered resend from a failed attempt.

The selected template value is also only written to the ledger; the implementation does not send the documented gentle, follow-up, or final-notice template. It merely requests that Stripe resend the invoice.

Attack Path

  1. An invoice remains unpaid.
  2. An operator or automation invokes send-reminder for that invoice.
  3. Stripe rejects the resend, rate-limits the request, encounters a transient failure, or determines that the invoice cannot be resent.
  4. The catch block prints the error but does not rethrow it or mark the operation as failed.
  5. Execution reaches logEvent() and appends `e ...[truncated 886 chars]
Remediation
View remediation

Remediation Suggestions

  1. Move the reminder_sent call inside the successful branch immediately after sendInvoice() resolves.
  2. In the catch branch, append a separate reminder_failed event containing the invoice ID, attempted template, timestamp, and a sanitized Stripe error code.
  3. Set a nonzero process exit code or rethrow the error so invoking automation can detect the failure.
  4. Do not record success until Stripe returns a successful API response.
  5. Track an idempotency key or attempt identifier to prevent duplicate or ambiguous reminder records.
  6. Implement the documented reminder templates through an appropriate email provider if those templates are intended to be delivered; otherwise, revise the documentation to state that Stripe only resends the original invoice.
  7. Add tests covering successful sends, Stripe rejections, rate limits, network failures, and attempts involving already-paid invoices.
  8. Reconcile ledger events against provider responses before using them for escalation or collection decisions.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (23)

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding

Most of the declared description matches the code: it uses Stripe to create payment links, create/send invoices, check invoice payment status, and send reminders by re-sending invoices. It also supports multi-currency in the sense that commands accept a currency parameter. However, there is a material description/behavior mismatch because the code includes undeclared capabilities (listing unpaid invoices and processing refunds) and does not implement a declared capability (recurring payments/subscriptions). The local ledger logging is a supporting implementation detail, not a primary mismatch.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
78% confidence
Finding

The skill explicitly requires ongoing tracking of invoices, payment status, and reminders, and later instructs persistence to local ledger/dashboard files. Persistent financial state increases exposure if stored insecurely or retained longer than necessary, particularly because it can include invoice IDs, mission IDs, amounts, and payment events.

Content

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

md
# CashClaw Invoicer

You handle all payment operations for CashClaw. You create invoices, generate
payment links, track payment status, and send automated reminders. Every dollar
earned must be tracked accurately. This is the skill that turns delivered work
into collected revenue.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The skill instructs reading the Stripe secret key from a local config file in addition to an environment variable, which expands credential exposure surfaces and encourages storage of a highly sensitive API secret in plaintext user-controlled storage. Local config files are more likely to be accidentally committed, backed up insecurely, or read by other tooling on the host.

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

Using Stripe API Directly (curl)

If the script is unavailable, use curl with the Stripe API:

bash
# Create a customer

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

bash
# Create a customer
curl https://api.stripe.com/v1/customers \
  -u "$STRIPE_SECRET_KEY:" \
  -d "email=client@example.com" \
  -d "name=Client Name" \

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

bash
# Create a customer
curl https://api.stripe.com/v1/customers \
  -u "$STRIPE_SECRET_KEY:" \
  -d "email=client@example.com" \
  -d "name=Client Name" \

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

bash
# Create a customer
curl https://api.stripe.com/v1/customers \
  -u "$STRIPE_SECRET_KEY:" \
  -d "email=client@example.com" \
  -d "name=Client Name" \

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

bash
# Create a customer
curl https://api.stripe.com/v1/customers \
  -u "$STRIPE_SECRET_KEY:" \
  -d "email=client@example.com" \
  -d "name=Client Name" \

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

bash
# Create a customer
curl https://api.stripe.com/v1/customers \
  -u "$STRIPE_SECRET_KEY:" \
  -d "email=client@example.com" \
  -d "name=Client Name" \

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

bash
# Create a customer
curl https://api.stripe.com/v1/customers \
  -u "$STRIPE_SECRET_KEY:" \
  -d "email=client@example.com" \
  -d "name=Client Name" \

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

bash
# Create a customer
curl https://api.stripe.com/v1/customers \
  -u "$STRIPE_SECRET_KEY:" \
  -d "email=client@example.com" \
  -d "name=Client Name" \

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

bash
# Create a customer
curl https://api.stripe.com/v1/customers \
  -u "$STRIPE_SECRET_KEY:" \
  -d "email=client@example.com" \
  -d "name=Client Name" \

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

bash
# Create a customer
curl https://api.stripe.com/v1/customers \
  -u "$STRIPE_SECRET_KEY:" \
  -d "email=client@example.com" \
  -d "name=Client Name" \

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

bash
# Create a customer
curl https://api.stripe.com/v1/customers \
  -u "$STRIPE_SECRET_KEY:" \
  -d "email=client@example.com" \
  -d "name=Client Name" \

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

bash
# Create a customer
curl https://api.stripe.com/v1/customers \
  -u "$STRIPE_SECRET_KEY:" \
  -d "email=client@example.com" \
  -d "name=Client Name" \

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

bash
# Create a customer
curl https://api.stripe.com/v1/customers \
  -u "$STRIPE_SECRET_KEY:" \
  -d "email=client@example.com" \
  -d "name=Client Name" \

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

bash
# Create a customer
curl https://api.stripe.com/v1/customers \
  -u "$STRIPE_SECRET_KEY:" \
  -d "email=client@example.com" \
  -d "name=Client Name" \

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The skill directs storage of client and payment-related events in local ledger and dashboard files without any privacy, retention, encryption, or access-control guidance. This can expose sensitive business and personal data to other local users, backups, logs, or accidental disclosure, especially on shared systems.

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

bash
# Full refund
curl https://api.stripe.com/v1/refunds \
  -u "$STRIPE_SECRET_KEY:" \
  -d "payment_intent=pi_xxxxx"

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · scripts/stripe-ops.js (reported line 10)May include surrounding context.

js
*   node stripe-ops.js <command> [options]
 *
 * Commands:
 *   create-link     Create a Stripe payment link
 *   create-invoice  Create and send a Stripe invoice
 *   check-status    Check payment status of an invoice
 *   send-reminder   Send a payment reminder

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The manifest describes invoice creation, payment link generation, payment status tracking, and automated reminders via Stripe, but it does not mention issuing refunds. Adding a refund command introduces a separate money-movement capability beyond the described invoicing workflow.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The refund path calls Stripe's refund API immediately based only on CLI arguments, with no interactive confirmation, dry-run, second factor, or policy check. In an agent or automation context, this increases the chance of accidental or unauthorized refunds causing direct financial loss and operational abuse.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Low
Category
Not specified by scanner
Confidence
91% confidence
Finding

The manifest description scopes the skill to invoice creation, payment link generation, payment status tracking, automated reminders, multi-currency billing, and recurring payments. The file additionally documents end-to-end refund handling, which is a distinct payment operation not mentioned in the manifest description.

Content

No source excerpt is available for this finding.