T09 · Insecure Skill Coding Practices
- Location
process_receipts.py:147- Finding
API-Controlled Path Traversal During Receipt Renaming
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This receipt-bookkeeping skill does what it advertises, but it uploads sensitive receipts to a remote API while also claiming to be local-first, and its file-renaming code trusts API data too much.
Install only if you are comfortable sending receipt and invoice contents to the Recite remote API. Use a restricted receipt folder, back up files first, prefer an environment variable or protected secret store for the API key, review long_term_memory.md before runs, and treat the generated CSV as untrusted before opening it in spreadsheet software.
process_receipts.py:147API-Controlled Path Traversal During Receipt Renaming
process_receipts.py:81Spreadsheet Formula Injection in Generated Bookkeeping CSV
README.md:29Unpinned Third-Party Dependency Installation
The skill sends receipt contents to an external API for extraction, but the description does not clearly warn users that sensitive financial documents and likely associated metadata will leave the local environment. Receipts and invoices often contain personally identifiable, financial, tax, and vendor information, so undisclosed exfiltration to a third party materially increases privacy and compliance risk.
The skill instructs use of a remote Vision API to scan receipts, which may contain financial and personal information, but does not prominently warn about the privacy implications of transmitting those documents off-device. In an agent context, this omission is dangerous because an automated system may upload sensitive receipts without the user realizing third-party processing is involved.
The README presents the skill as 'Local-First' even though receipt images and PDFs are sent to a remote Vision API for extraction. This can mislead users and downstream agents about where sensitive financial documents are processed, reducing informed consent and increasing the chance that confidential data is uploaded unexpectedly.
The README directs agents to 'Always read' a long-term memory file containing persistent instructions, creating a persistent context injection surface. If that file is modified by an attacker or populated with unsafe directives, future agent runs may inherit untrusted instructions that alter behavior, exfiltrate data, or override user intent.
- **Smart Renaming:** Automatically renames files to `[YYYY-MM-DD]_[Vendor].png/pdf`.
- **Schema-Aware Bookkeeping:** Appends data to `bookkeeping_transactions.CSV`. Handles API response changes without data loss.
- **Local-First:** Keeps your financial data on your machine.
- **Long-Term Memory:** Supports custom persistent instructions (e.g., "Alert if total > $500").
## 🛠️ Setup
Persisting the API key in ~/.config/recite/config.json creates a session-persistent secret that may be exposed through weak file permissions, backups, multi-user systems, or later agent access. While common operationally, it increases the attack surface compared with ephemeral secret handling, especially for a skill that interacts with external services and local files.
Set the API key in your environment or configuration file:
- **Environment:** `export RECITE_API_KEY="re_live_YOUR_API_KEY"`
- **Config:** Create `~/.config/recite/config.json` with `{"api_key": "re_live_..."}`.
### 2. Dependencies
Ensure you have `python3`, `requests`, and `csv` installed.
The documentation states the agent MUST verify the Recite API key before performing any scanning, file manipulation, or even listing files. However, the same document presents direct invocation of process_receipts.py as the tool entrypoint, with no indication of an enforced guard in the skill file itself, creating an intent-versus-execution divergence in the documented behavior.
The skill performs destructive or state-changing local actions by renaming files and writing bookkeeping data to disk, but the description does not clearly foreground those side effects as a user warning. That can lead to unintended file mutations, broken user workflows, or accidental processing of sensitive financial records without informed consent.
The skill instructs the agent to always read a mutable long_term_memory.md file before processing, creating a persistent prompt-injection surface. Anyone able to modify that file can silently alter future behavior, including causing unauthorized file operations, data disclosure, or policy bypasses across sessions.
## Long-Term Memory & Custom Logic
Modify `skills/recite/long_term_memory.md` to add persistent instructions for the agent. The agent will always read this file before processing.
Examples:
- "After processing, move all files to a sub-folder named `processed/`."
Skill injects content designed to persist in agent memory or context across interactions. Persistent injection can alter agent behavior long after the initial interaction.
# Recite Long-Term Memory (Persistent Instructions)
This file contains persistent instructions for the Recite agent. Modify this file to customize your bookkeeping workflow.
Skill injects content designed to persist in agent memory or context across interactions. Persistent injection can alter agent behavior long after the initial interaction.
# Recite Long-Term Memory (Persistent Instructions)
This file contains persistent instructions for the Recite agent. Modify this file to customize your bookkeeping workflow.
## Custom Workflow Instructions
- **File Organization:** After scanning, you can instruct the agent to move files to specific sub-folders (e.g., `processed/2026/`).
This code performs a network POST to an external API and includes the full receipt image/PDF content in the request body. In the context of bookkeeping receipts, that data can include names, addresses, payment details, itemized purchases, and other confidential business or personal information, making outbound transmission security-relevant and potentially harmful if users are unaware or the service is untrusted.
}
try:
response = requests.post(f"{BASE_URL}/scan", headers=headers, json=payload, timeout=30)
if response.status_code == 200:
return response.json()
else:
The script base64-encodes local receipt files and sends their full contents to a third-party API endpoint for processing, but it does not provide any explicit notice, consent flow, or data-minimization controls. Receipts commonly contain sensitive financial and personal information, so silent transmission to an external service creates a real confidentiality and privacy risk even if the feature is functionally intended.
No suspicious patterns detected.