Back to skill

Security audit

QuickBooks

Security checks for vulnerabilities and agentic risk

Overview

The skill is a disclosed QuickBooks MCP integration scaffold that handles OAuth setup locally, with supply-chain and credential-storage risks users should manage but no evidence of deception or exfiltration.

Install only if you trust Maverick and the mcporter package path for QuickBooks access. Pin mcporter where possible, run under a least-privileged account, ensure ~/.mcporter/credentials.json is readable only by the owning user, and treat any write-capable QuickBooks operation as financially impactful.

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

T08 · Insecure Dependencies

Warning
Location
SKILL.md:15
Finding

Unpinned mcporter Dependency Creates Supply-Chain Execution Risk

Content
View full analysis

Vulnerability Details

File Location: SKILL.md:15-20
Vulnerability Type: Unpinned automatically installed npm dependency
Risk Level: Medium

Vulnerable Code

yaml
install:
  - id: node
    kind: node
    package: mcporter
    bins:
      - mcporter

The dependency documentation at SKILL.md:46 explicitly confirms that this resolves the unpinned latest release:

markdown
- **`mcporter`** ([github.com/steipete/mcporter](https://github.com/steipete/mcporter)) — MCP CLI used by the shared wrapper once a QuickBooks MCP manifest exists. Auto-installed via `npm install -g --ignore-scripts mcporter` if missing on PATH (see `install` spec in frontmatter). The install spec uses unpinned `mcporter` (npm `latest`); operators with strict supply-chain controls should override the install to pin a specific version (e.g. `mcporter@<version>`).

Technical Analysis

The installation specification names mcporter without an exact version or integrity constraint. Consequently, installation may resolve to whichever release is tagged as latest at that time rather than to the release reviewed with this Skill.

Disabling npm lifecycle scripts with --ignore-scripts reduces install-time exposure but does not remove the risk. The installed package's executable is subsequently launched by scripts/invoke.sh:17:

bash
exec env MCPORTER_CONFIG="${CONFIG}" mcporter "$@"

If the npm package, publisher account, or latest release were compromised, attacker-controlled code in the executable would run with the privileges of the Skill's runtime user. This is a supply-chain risk rather than evidence that the current package is malicious.

Attack Path

  1. An attacker compromises the upstream npm package, a maintainer account, or a release assigned the latest tag.
  2. The runtime cannot find mcporter and automatically installs the dependency without an exact version.
  3. npm resolves a ...[truncated 1246 chars]
Remediation
View remediation

Remediation Suggestions

  1. Pin mcporter to a specific, reviewed version, such as mcporter@X.Y.Z, instead of resolving the mutable latest tag.
  2. Enforce npm integrity verification through an approved lockfile or expected package digest.
  3. Prefer a project-local installation over a global installation to reduce scope and improve reproducibility.
  4. Retrieve packages only from an explicitly configured, trusted registry; consider an internal artifact mirror for controlled deployments.
  5. Continue using --ignore-scripts, but do not treat it as a substitute for version and integrity pinning.
  6. Review dependency updates before changing the pinned version and automate vulnerability and provenance checks.
  7. Run the wrapper under a dedicated least-privileged account with access limited to the required QuickBooks credentials and files.
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • 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
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (5)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The declared description focuses on using QuickBooks integration context for financial entities and reports, implying an operational integration layer for QuickBooks data. The actual code does not access QuickBooks customers, invoices, payments, vendors, expenses, or reports at all. Instead, it is an infrastructure/setup script for storing OAuth credentials for a generic MCP server in a local mcporter vault. While the description briefly mentions runtime OAuth credentials and lack of a registered manifest, this code's primary purpose is credential seeding/provisioning rather than QuickBooks data integration. That is a materially different behavior and should be flagged as a mismatch.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The declared purpose is specifically about QuickBooks integration context for customers, invoices, payments, expenses, vendors, and financial reports. However, the provided code does not implement or expose any QuickBooks-specific behavior. Instead, it is a universal wrapper for launching mcporter based on a local manifest file. This is a materially different primary purpose from the declared description. While wrapper scripts can be supporting details, this chunk also contradicts the description's note that there is no provider-owned MCP manifest registered in the repository, because it requires a local mcporter.json with an mcpServers entry to function. Therefore, the description does not accurately represent what this code chunk actually does.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/init-mcporter.sh (reported line 4)May include surrounding context.

sh
#!/usr/bin/env bash
# init-mcporter.sh — vault seeder for HTTP+OAuth MCP servers.
#
# Reseeds ~/.mcporter/credentials.json when (a) the env-supplied refresh_token
# differs from the skill-owned provision marker, or (b) the vault entry is
# missing entirely. No-op when both match. The provisioner (whichever upstream
# system supplies the env tokens — typically via OpenClaw config.patch)

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/init-mcporter.sh (reported line 17)May include surrounding context.

sh
#   ${prefix}REFRESH_TOKEN  required
#   ${prefix}CLIENT_ID      required (DCR-issued)
#   ${prefix}ACCESS_TOKEN   required (the provisioner has both tokens at OAuth
#                                     completion; seeding the access token
#                                     skips mcporter's first-request 401→refresh)
#
# Vault key from steipete/mcporter src/oauth-vault.ts:

Credential Access

High
Category
Privilege Escalation
Confidence
83% confidence
Finding

The script writes live access and refresh tokens into ${HOME}/.mcporter/credentials.json but does not explicitly enforce restrictive file permissions on the vault or its temporary files. If the host umask is permissive or the home directory is shared, other local users or processes could read reusable OAuth credentials and gain access to QuickBooks data.

Content

Scanner excerpt · scripts/init-mcporter.sh (reported line 46)May include surrounding context.

sh
mcp_client_id="${!mcp_client_id_var:?${mcp_client_id_var} required}"
mcp_access="${!mcp_access_var:?${mcp_access_var} required}"

mcp_vault="${HOME}/.mcporter/credentials.json"
mcp_descriptor=$(jq -cn --arg n "${mcp_server}" --arg u "${mcp_url}" \
  '{name:$n, url:$u, command:null}')
mcp_hash=$(printf '%s' "${mcp_descriptor}" | shasum -a 256 | cut -c1-16)