Back to skill

Security audit

drivethru-payable-matching

Security checks for vulnerabilities and agentic risk

Overview

This skill performs sensitive live payable-matching work, but the artifacts clearly disclose the Odoo access, financial writes, posting safeguards, local helper scripts, and credential requirements.

Install only for an agent authorized to modify BaconCo/Odoo purchasing and payables records. Confirm it is connected to the intended Odoo environment, protect ODOO_MCP_TOKEN and SPORTSINC_API_KEY, prefer draft or dry-run mode for first runs, and periodically clean or restrict any rendered invoice image directories.

Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Rogue AgentSelf-Modification, Session Persistence
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (8)

subprocess module call

Medium
Category
Dangerous Code Execution
Content
if not py.exists():
        _VENV.parent.mkdir(parents=True, exist_ok=True)
        subprocess.run([uv, "venv", str(_VENV)], check=True, stdout=sys.stderr)
    subprocess.run(
        [uv, "pip", "install", "--python", str(py), *REQUIREMENTS],
        check=True,
        stdout=sys.stderr,
Confidence
91% confidence
Finding
This code installs Python packages at runtime by invoking `uv pip install`, which creates a supply-chain execution path during normal skill operation. Although `subprocess.run` is used safely without a shell, the behavior is still dangerous because it pulls and installs executable dependencies from the environment at run time, trusting PATH resolution for `uv` and network/package sources; a compromised PATH, package index, or dependency chain could lead to arbitrary code execution.

os.system() or os exec-family call

High
Category
Dangerous Code Execution
Content
# Re-run the exact same command under the venv interpreter; on that second
    # entry ensure() finds everything present and returns immediately.
    os.execv(str(py), [str(py), *sys.argv])
Confidence
86% confidence
Finding
`os.execv` replaces the current process with the interpreter from the newly created virtual environment, inheriting command-line arguments unchanged. In isolation this is a normal re-exec pattern, but here it compounds the risk of the preceding runtime bootstrap: once a potentially untrusted interpreter/environment is prepared, control is transferred to it immediately, enabling execution of code from that environment without additional validation.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
# uv chatter goes to stderr so the script's JSON stdout stays clean.
    if not py.exists():
        _VENV.parent.mkdir(parents=True, exist_ok=True)
        subprocess.run([uv, "venv", str(_VENV)], check=True, stdout=sys.stderr)
    subprocess.run(
        [uv, "pip", "install", "--python", str(py), *REQUIREMENTS],
        check=True,
Confidence
84% confidence
Finding
Creating a virtual environment via external `uv` execution is part of a self-bootstrap chain that modifies the local runtime environment during skill execution. The direct subprocess usage is not shell-injection-prone, but it still relies on locating `uv` from PATH and writing into a directory influenced by `PAYMATCH_DATA_DIR`, which can be abused in a hostile or multi-tenant host setup to redirect environment creation or interfere with trusted execution.

Lp3

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding
The skill clearly uses sensitive capabilities including environment secrets, MCP access to Odoo, and shell execution, yet it does not declare explicit permissions. That weakens governance and increases the chance the skill is granted broader access than reviewers or operators realize, especially because it can modify live financial records and post bills.

Intent-Code Divergence

Medium
Confidence
78% confidence
Finding
The document defines an exactly-once invariant around marking SportsLink invoices historical only after safe billing state is established, but later multi-invoice guidance relaxes that rule enough to allow a document to be marked consumed after mere bill creation, including unreconciled drafts. If an operator or agent follows the weaker interpretation, invoices with unresolved discrepancies can disappear from the active queue and evade human review, causing accounting gaps or missed liabilities.

Missing User Warnings

Medium
Confidence
81% confidence
Finding
The skill instructs an agent to create vendor bills, post them to the ledger, and mark source invoices consumed, which are financially significant and partly irreversible actions. Without an upfront warning about live financial mutations, users may invoke the workflow in the wrong environment or without understanding that it changes accounting records and source-system state.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The `render` path writes rendered document pages to disk under a temp or caller-supplied directory and returns those filesystem paths, but the code does not clean them up or enforce restrictive permissions/lifetime controls. Because these documents are payable/invoice records, they can contain sensitive financial and vendor data that may remain accessible to other local users, later processes, logs, or tooling on the host.

Session Persistence

Medium
Category
Rogue Agent
Content
`Questions` subfolder — escalating genuine questions to a reviewer (default
  Zach Tucker). Also runs the buying-group payables flow: pull Sports Inc
  invoices from the SportsLink API (via the `sportsinc-sportslink` adapter),
  reconcile each to its PO, correct price variances, create the vendor bill and
  — when the bill total matches the invoice within tolerance — POST it, leaving
  any mismatch in draft for a human ("get the Sports Inc invoices and bill
  them", "match the SI invoices to POs and post the payables", "match the vendor
Confidence
83% confidence
Finding
The skill is designed to create and post vendor bills, move documents, and leave persistent notes as part of a batch workflow, which creates durable state changes across sessions. In this context, persistence is risky because a mistaken match, bad extraction, or adversarial document content can lead to incorrect financial postings that are harder to reverse than a transient response.

Static analysis

No suspicious patterns detected.