Back to skill

Security audit

Maybe Finance - 个人财务助手

Security checks for vulnerabilities and agentic risk

Overview

The skill does not look like malware, but it should be reviewed because it asks for finance API credentials while the included CLI mostly returns mock data and can falsely report that transactions were added.

Review carefully before installing. Do not rely on this skill for real financial records unless the CLI is changed to clearly run in demo mode or to make verified Maybe API calls. If used, pin the Maybe container image, bind it only where intended, protect the API token, and require explicit confirmation or backups before any destructive account operation.

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

T08 · Insecure Dependencies

Warning
Location
SKILL.md:23
Finding
Unpinned Mutable Container Image Used as a Runtime Dependency<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, line 23 **Vulnerability Type**: `T08: Insecure Dependencies` **Risk Level**: Medium ### Vulnerable Code ```bash docker run -d -p 3000:3000 ghcr.io/maybe-finance/maybe:latest ``` ### Technical Analysis The documented deployment command executes the `latest` tag of a third-party container image. A mutable tag does not identify a fixed, previously reviewed artifact. The image associated with this tag may change between installations without any corresponding modification to this skill package. The command also publishes container port 3000 on every host interface by default. Consequently, whatever application version the mutable tag resolves to may become reachable over the host network. There is no evidence in the audited files that the current upstream image is malicious. The vulnerability is the absence of immutable version and digest pinning, which leaves future installations dependent on the security and continued integrity of a mutable upstream artifact. ### Attack Path 1. An attacker compromises the upstream image repository, its publication credentials, or the build process responsible for `ghcr.io/maybe-finance/maybe:latest`. 2. The attacker replaces or updates the mutable tag with a modified image. 3. A user follows the prerequisite documentation and runs the provided Docker command. 4. Docker retrieves the altered image if it is not already cached locally, or after the tag is refreshed. 5. The attacker-controlled image executes inside the container and exposes its service through host port 3000. 6. The resulting impact depends on the Docker configuration, mounted resources, container privileges, and vulnerabilities in the container runtime. ### Impact Assessment The altered image would obtain code execution within the launched container. It could access data and credentials made available to that container and interact with reachable network services. The published port could exp ...[truncated 412 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Replace `latest` with a reviewed, explicit release version. 2. Pin the image by immutable SHA-256 digest, for example: ```bash docker run -d \ -p 127.0.0.1:3000:3000 \ ghcr.io/maybe-finance/maybe@sha256:REVIEWED_DIGEST ``` 3. Record the corresponding semantic version and a documented process for reviewing and updating the digest. 4. Verify image signatures or provenance attestations before deployment where supported. 5. Bind the service to `127.0.0.1` unless remote access is explicitly required. 6. Run the container as a non-root user with a read-only filesystem, dropped Linux capabilities, resource limits, and no unnecessary host mounts. 7. Scan the pinned image for known vulnerabilities before recommending it to users. ]]>

other

Warning
Location
scripts/maybe-cli.py:119
Finding
Transaction Creation Reports Success Without Persisting Financial Data<![CDATA[ ## Vulnerability Details **File Location**: `scripts/maybe-cli.py`, lines 119-125; documented behavior in `SKILL.md`, lines 51-55 and 85-87 **Vulnerability Type**: `other: Misleading Functionality` **Risk Level**: Medium ### Vulnerable Code The documentation represents the command as an operation that adds a transaction: ```bash # Add income maybe-finance transactions add --amount 10000 --type income --category "工资" --description "三月工资" # Add expense maybe-finance transactions add --amount -150 --type expense --category "餐饮" --description "午餐" ``` The complete implementation of the corresponding handler only prints a success message: ```python def transactions_add(args): """Add a new transaction.""" print(f"✅ Transaction added:") print(f" Amount: {format_currency(args.amount)}") print(f" Type: {args.type}") print(f" Category: {args.category}") print(f" Description: {args.description}") ``` ### Technical Analysis The `transactions_add` function does not invoke `make_api_request`, write to a file, update a database, or otherwise persist the supplied transaction. Nevertheless, it unconditionally prints `Transaction added`, presenting a failed or nonexistent write as successful. This behavior is part of a broader discrepancy between the documentation and reachable implementation. The account and transaction listing functions use hard-coded demonstration records, and the API request helper is not called by the routed commands. Therefore, command output cannot be relied on as a representation of the configured Maybe Finance instance. This is not evidence of credential theft or malicious execution. It is an integrity and reliability issue that is especially significant because the skill handles personal financial records. ### Attack Path 1. A user configures `MAYBE_API_URL` and `MAYBE_API_TOKEN` as directed. 2. The user invokes `transactions add` with a legitimate income or expense record. 3. The handler accepts the arg ...[truncated 1143 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Implement transaction creation through the configured Maybe Finance API and only report success after receiving and validating a successful response. 2. Return a nonzero exit status for authentication failures, validation failures, network errors, and rejected writes. 3. Display the server-generated transaction identifier and persisted values so callers can verify the result. 4. Add an optional read-after-write verification step for financial operations. 5. Clearly label any demonstration mode and require an explicit flag such as `--demo`; never mix hard-coded sample data with normal production commands. 6. Replace hard-coded account, transaction, budget, net-worth, and cash-flow values with live API results, or remove the unsupported commands. 7. Add automated tests using a mock HTTP server to confirm that write commands issue the expected request and do not print success after an error. 8. Update `SKILL.md` so that it documents only implemented behavior, including limitations and failure modes. ]]>
Vulnerability Patterns
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
Findings (9)

Tainted flow: 'req' from os.getenv (line 40, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Content
method=method
            )
        
        with urllib.request.urlopen(req, timeout=30) as response:
            return json.loads(response.read().decode())
    except urllib.error.HTTPError as e:
        print(f"Error: API request failed - {e.code} {e.reason}")
Confidence
90% confidence
Finding
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Lp3

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding
The skill documents use of environment variables for secrets and a self-hosted HTTP API, but it does not declare any explicit tool scope or permissions boundaries. That creates an authorization gap where an agent using the skill could access env/network capabilities more broadly than users expect, increasing the risk of secret exposure or unintended outbound requests in a finance context.

Rp1

Medium
Category
MCP Rug Pull
Confidence
81% confidence
Finding
The deployment example pulls a container image using a mutable latest tag rather than a pinned version or digest. This creates a supply-chain risk because future pulls may retrieve unexpected or compromised code, which is especially sensitive for software handling financial data and API tokens.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
The skill includes a destructive account deletion command with no warning, confirmation, backup guidance, or distinction between test and production use. In a personal finance system, accidental or automated deletion could cause irreversible data loss, broken reports, and loss of audit history.

Description-Behavior Mismatch

Medium
Confidence
96% confidence
Finding
The module docstring and manifest describe a personal finance management tool for the Maybe Finance self-hosted platform, implying real account, transaction, budget, and net worth operations. However, the command handlers at L72-L198 only print static mock datasets or echo user input, and the API helper defined at L25-L61 is never used.

Rp1

Medium
Category
MCP Rug Pull
Confidence
75% confidence
Finding
Docker image references without a specific tag (:latest is implicit) or digest (@sha256:...) can be silently replaced by a malicious image.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
This code hard-codes Chinese labels such as account names and totals, and formats all values with the yuan symbol, while also presenting some headings in English. That constitutes a locale/language policy issue because users are not given any opt-in or configuration choice for language or regional formatting.

Intent-Code Divergence

Medium
Confidence
95% confidence
Finding
The docstring at L116 states that the function adds a new transaction, which implies a state-changing operation against the finance platform. In reality, the function just echoes the provided fields to stdout and performs no API call, storage update, or other persistence.

Natural-Language Policy Violations

Low
Confidence
83% confidence
Finding
The usage examples hard-code Chinese text values such as "工资", "三月工资", and "餐饮" in a general-purpose skill description. Because the skill is not documented as China-specific and does not offer language choice, this creates a natural-language locale policy concern.

Static analysis

No suspicious patterns detected.