Back to skill

Security audit

Subscription Revenue Tracker

Security checks for vulnerabilities and agentic risk

Overview

This finance skill is mostly an analysis guide, but it needs review because its examples encourage unsafe handling of live Stripe keys.

Review before installing. If used, replace the Stripe examples with environment variables or a secret manager, prefer test-mode or restricted read-only Stripe keys, avoid pasting secrets into shell commands, and independently verify the accounting calculations and the claimed Chargebee/QBO integration scope.

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

T09 · Insecure Skill Coding Practices

Error
Location
SKILL.md:70
Finding

Unsafe Handling of Live Stripe API Secret Keys

Content
View full analysis

Vulnerability Details

File Location: SKILL.md, lines 70-71 and 86
Vulnerability Type: Hardcoded and command-line API credentials
Risk Level: High

Vulnerable Code

bash
curl "https://api.stripe.com/v1/subscriptions?status=active&limit=100&expand[]=data.items.data" \
  -u sk_live_YOUR_KEY: | jq '
python
stripe.api_key = "sk_live_YOUR_KEY"

Technical Analysis

The examples use a placeholder rather than an actual credential, but they instruct users to replace it with a live Stripe secret key. The curl example places the credential directly in a command-line argument. Depending on the operating system and execution environment, the resulting secret may be exposed through shell history, process inspection, command auditing, terminal capture, or CI/CD logs.

The Python example encourages embedding the live key directly in source code. A user following this pattern could inadvertently commit the credential to version control or expose it through shared files, backups, support bundles, logs, or generated artifacts. Removing a key from the latest revision would not eliminate it from repository history.

This is an insecure credential-handling pattern under T09: Insecure Skill Coding Practices. No actual live key was found in the audited file.

Attack Path

  1. A user replaces sk_live_YOUR_KEY with a valid Stripe secret key.
  2. The user executes the curl command or saves the Python example with the embedded credential.
  3. The credential is retained in shell history, exposed in process or audit data, captured in logs, or committed to a repository.
  4. An attacker or unauthorized local user obtains access to one of those sources.
  5. The attacker extracts the Stripe secret and authenticates to the Stripe API.
  6. The attacker accesses the data and operations permitted by that key until it is revoked or rotated.

Impact Assessment

Successful exploitation could expose ...[truncated 523 chars]

Remediation
View remediation

Remediation Suggestions

  1. Read the Stripe key from a protected environment variable or secret manager instead of embedding it in source code:

    python
    import os
    import stripe
    
    stripe.api_key = os.environ["STRIPE_API_KEY"]
    
  2. Avoid passing the credential directly as a command-line argument. Configure curl through a protected configuration file or use a small client that reads the secret from the environment without printing it. If a configuration file is used, restrict its permissions to the owning user.

  3. Use a Stripe restricted key granting only the read permissions required for subscription analytics. Do not recommend a full-access live key when read-only access is sufficient.

  4. Ensure secrets are masked in CI/CD output and excluded from command tracing, debug logs, notebooks, generated reports, and support bundles.

  5. Add secret-bearing files to .gitignore and enable automated secret scanning or pre-commit checks. Environment template files should contain variable names only, never real values.

  6. Document an incident response procedure requiring immediate key revocation and rotation if a credential is entered into shell history, committed to a repository, or otherwise exposed.

Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (4)

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The skill includes examples using a live Stripe secret key format directly in commands and code, without an explicit warning to use environment variables, test keys, or secret-management practices. In a finance skill handling subscription data, this increases the risk that users hardcode real credentials into shell history, scripts, notebooks, or shared docs, leading to credential exposure and unauthorized access to billing data.

Content

No source excerpt is available for this finding.

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

Get MRR summary via Stripe API (no CLI):

bash
curl "https://api.stripe.com/v1/subscriptions?status=active&limit=100&expand[]=data.items.data" \
  -u sk_live_YOUR_KEY: | jq '
  [.data[] | 
    (.items.data[0].price.unit_amount / 100) *

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The comment at L456 says the example produces '12 monthly recognition of $1,000 each', but the code above computes revenue per period using period_days / total_days and rounds each month individually. That means month amounts vary by month length and are not all exactly $1,000, so the inline documentation actively contradicts the implemented accounting logic.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

The manifest and CSV loader docstring imply direct Chargebee connectivity, but the file contains only Stripe API examples and a generic CSV reader. This is not merely missing detail: the documentation suggests a concrete integration path that the code does not implement.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.