Back to skill

Security audit

Accounting Assistant

Security checks for vulnerabilities and agentic risk

Overview

This accounting skill is not clearly malicious, but it handles sensitive financial records and includes unsafe file and CSV output behavior that deserves manual review before installation.

Install only if you are comfortable reviewing and constraining the scripts yourself. Run them only on trusted accounting files, avoid broad folders, do not open exported CSVs from untrusted input without sanitization, and choose explicit safe output directories. The skill should be fixed to add privacy warnings, path containment, overwrite protection, CSV formula neutralization, and accurate usage documentation.

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

T09 · Insecure Skill Coding Practices

Warning
Location
datev-export.py:81
Finding
Spreadsheet Formula Injection in DATEV CSV Exports## Vulnerability Details **File Location**: `datev-export.py:81-82, 112, 142-143` **Vulnerability Type**: CSV/spreadsheet formula injection **Risk Level**: Medium ### Vulnerable Code ```python beschreibung = buchung.get('beschreibung') or buchung.get('anbieter', '') ``` ```python row = [ f"{betrag:.2f}", # Umsatz soll_haben, # Soll/Haben 'EUR', # WKZ '', # Kurs '', # Basis-Umsatz '', # WKZ Basis konto, # Konto gegenkonto, # Gegenkonto beleg, # Belegfeld1 beleg_datum, # Belegfeld2 '', # Skonto beschreibung, # Buchungstext '', # Postensperre '', # Adressfelder '', # Geschäftspartnerbank '', # Sachverhalt '', # Zahlweise '', # Forderungsart '', # Veranlagungsnummer '', # Ausstellungsdatum buch_datum, # Datum steuercode, # Steuercode ] rows.append(row) ``` ```python writer = csv.writer(output, delimiter=';') writer.writerow(header) writer.writerows(rows) ``` ### Technical Analysis Booking descriptions and vendor names can originate from externally supplied accounting records. These values are placed into spreadsheet-compatible CSV cells without neutralizing characters that spreadsheet applications interpret as formulas, including `=`, `+`, `-`, `@`, tab, and carriage return. CSV quoting only preserves field boundaries; it does not prevent spreadsheet software from interpreting a quoted value as a formula. Consequently, a value such as `=HYPERLINK("https://attacker.example","Open")` may be evaluated when the resulting DATEV CSV is opened. ### Attack Path 1. An attacke ...[truncated 949 chars]
Remediation
## Remediation Suggestions - Apply a shared sanitization function to every untrusted text cell before CSV serialization. - Prefix values beginning with `=`, `+`, `-`, `@`, tab, or carriage return with an apostrophe or otherwise encode them according to the target DATEV workflow. - Validate dates, account numbers, categories, invoice identifiers, and monetary values against strict allowlists. - Treat descriptions and vendor names as untrusted even when imported from internal accounting files. - Add regression tests using values such as `=1+1`, `+SUM(1,1)`, `@SUM(1,1)`, and tab-prefixed formulas.

T09 · Insecure Skill Coding Practices

Warning
Location
eur-erstellung.py:177
Finding
Spreadsheet Formula and Row Injection in EÜR CSV Reports## Vulnerability Details **File Location**: `eur-erstellung.py:177-190` **Vulnerability Type**: CSV/spreadsheet formula injection and unsafe manual CSV construction **Risk Level**: Medium ### Vulnerable Code ```python def _generate_csv(self, summen): import io output = io.StringIO() output.write("Kategorie;Typ;Monat;Betrag;Beschreibung\n") for kat, monate in self.einnahmen.items(): for monat, eintraege in monate.items(): for e in eintraege: output.write(f"{kat};Einnahme;{monat};{e['betrag']};{e['beschreibung']}\n") for kat, monate in self.ausgaben.items(): for monat, eintraege in monate.items(): for e in eintraege: output.write(f"{kat};Ausgabe;{monat};{e['betrag']};{e['beschreibung']}\n") return output.getvalue() ``` ### Technical Analysis Categories, months, amounts, and descriptions are interpolated directly into semicolon-delimited output. No spreadsheet formula neutralization or CSV quoting is performed. A description beginning with a formula marker can therefore be evaluated by spreadsheet software. Semicolons, quotation marks, carriage returns, or line feeds can also alter the generated row structure because the code constructs CSV records manually instead of using Python's `csv` module. Values loaded through `from_json()` can reach this output path as descriptions and booking fields, making malformed or hostile accounting input a viable source. ### Attack Path 1. A crafted booking is supplied through JSON or another caller of the public methods. 2. Its description starts with a formula marker or contains a newline and additional delimiters. 3. `from_json()` or `add_einnahme()`/`add_ausgabe()` stores the value unchanged. 4. `_generate_csv()` interpolates the value directly into the output. 5. The report is saved or redirected to a CSV file. 6. Opening the file in spre ...[truncated 477 chars]
Remediation
## Remediation Suggestions - Replace manual string interpolation with `csv.writer` configured with the required delimiter and quoting behavior. - Neutralize formula-leading characters in every untrusted string cell. - Reject or safely encode carriage returns and line feeds where multiline fields are unnecessary. - Validate the month against a strict format such as `YYYY-MM`. - Validate monetary values as finite decimal numbers rather than accepting arbitrary objects. - Add tests for formulas, delimiters, quotation marks, CRLF sequences, and multiline descriptions.

T09 · Insecure Skill Coding Practices

Warning
Location
rechnungs-generator.py:187
Finding
Path Traversal Through JSON-Controlled Invoice Number## Vulnerability Details **File Location**: `rechnungs-generator.py:187-211` **Vulnerability Type**: Path traversal and arbitrary writable-path file overwrite **Risk Level**: Medium ### Vulnerable Code ```python # Speichern if output_path is None: output_path = f'rechnungen/{rechnungs_nr}.pdf' os.makedirs(os.path.dirname(output_path), exist_ok=True) pdf.output(output_path) return output_path def rechnung_aus_json(json_path, output_dir='rechnungen'): """Erstellt Rechnung aus JSON-Datei""" with open(json_path, 'r', encoding='utf-8') as f: data = json.load(f) output_path = os.path.join(output_dir, f"{data['rechnungs_nr']}.pdf") return create_rechnung( rechnungs_nr=data['rechnungs_nr'], kunde_name=data['kunde']['name'], kunde_adresse=data['kunde']['adresse'], kunde_plz_ort=data['kunde']['plz_ort'], leistungen=data['leistungen'], ausstellungsdatum=data.get('datum'), output_path=output_path ) ``` ### Technical Analysis `rechnung_aus_json()` uses the JSON-controlled `rechnungs_nr` directly as part of an output path. Path separators and parent-directory components are not rejected, and the resolved destination is not checked for containment within `output_dir`. For example, an invoice number of `../../target` produces a path resembling `rechnungen/../../target.pdf`. The PDF generator then creates parent directories and writes to that escaped location. If the destination already exists and is writable, it may be overwritten. ### Attack Path 1. An attacker provides a JSON invoice accepted by `rechnung_aus_json()`. 2. The `rechnungs_nr` field contains traversal components, such as `../../target`. 3. `os.path.join()` constructs a path outside the intended `rechnungen` directory. 4. `create_rechnung()` creates the destination directory if necessary. 5. `pdf.output()` writes attacker-influenc ...[truncated 466 chars]
Remediation
## Remediation Suggestions - Restrict invoice numbers to a strict allowlist, such as `^[A-Za-z0-9_-]+$`. - Resolve both the output directory and destination with `pathlib.Path.resolve()`. - Verify that the resolved destination remains beneath the resolved output directory before writing. - Reject absolute paths, path separators, `.` components, and `..` components. - Refuse to overwrite existing files unless an explicit trusted overwrite option is enabled. - Open output files using exclusive-creation semantics where supported.

T09 · Insecure Skill Coding Practices

Warning
Location
rechnungs-generator-v2.py:280
Finding
Path Traversal Through Invoice Number in Version 2 Generator## Vulnerability Details **File Location**: `rechnungs-generator-v2.py:280-286` **Vulnerability Type**: Path traversal and arbitrary writable-path PDF overwrite **Risk Level**: Medium ### Vulnerable Code ```python # Speichern if output_path is None: output_dir = 'rechnungen' os.makedirs(output_dir, exist_ok=True) output_path = os.path.join(output_dir, f'{rechnungs_nr}.pdf') pdf.output(output_path) return output_path ``` ### Technical Analysis The public `create_rechnung()` function accepts `rechnungs_nr` and incorporates it directly into the default output path. No filename validation or resolved-path containment check is performed. If an untrusted caller controls the invoice number, parent-directory components can escape the `rechnungen` directory. Supplying an explicit `output_path` also permits arbitrary writes by design, so callers must be treated as trusted or constrained at the integration boundary. ### Attack Path 1. An application exposes `create_rechnung()` to untrusted invoice data. 2. The attacker supplies an invoice number such as `../../target`. 3. The default path becomes `rechnungen/../../target.pdf`. 4. `pdf.output()` resolves the traversal through the filesystem. 5. The generated PDF is written outside the intended invoice directory. 6. A writable existing `.pdf` file can be overwritten. ### Impact Assessment The issue permits creation or replacement of `.pdf` files within the filesystem permissions of the process. It can damage data or place misleading documents in unintended locations. It does not independently confer elevated operating-system privileges.
Remediation
## Remediation Suggestions - Validate `rechnungs_nr` with a strict filename-safe allowlist. - Resolve the candidate path and verify containment under the invoice output directory. - Separate invoice identifiers from filesystem names by generating a server-controlled filename. - Restrict explicit `output_path` usage to trusted internal callers. - Avoid overwriting existing output by default. - Add tests covering absolute paths, nested paths, encoded separators, and `..` traversal.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • 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 (16)

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
Die Beschreibung behauptet eine umfassende Buchhaltungs-Automatisierung inklusive EÜR-Erstellung, DATEV-Export und Steuer-Vorbereitung. Der vorliegende Code implementiert jedoch nur einen Teil davon: PDF-Beleganalyse mit Textextraktion, einfachen Regex-basierten Feldern, Anbieter-basierter Kategorisierung und Ausgabe einer Zusammenfassung. Es gibt keine Logik zur Erstellung einer EÜR, keinen Export in DATEV-Formate und keine weitergehende Steueraufbereitung. Damit ist die deklarierte Beschreibung wesentlich breiter als das tatsächliche Verhalten dieses Code-Chunks.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
Die Beschreibung verspricht mehrere Funktionen: EÜR-Erstellung, DATEV-Export, PDF-Beleganalyse und Steuer-Vorbereitung. Im vorliegenden Code ist nur die EÜR-Erstellung tatsächlich umgesetzt. Es werden Buchungen aus einer JSON-Datei eingelesen oder manuell hinzugefügt, Summen berechnet und Berichte als Markdown/CSV/JSON gespeichert. Es gibt keinen DATEV-spezifischen Export, keine Verarbeitung oder Analyse von PDFs und keine weitergehende Automatisierung typischer Buchhaltungsprozesse. Daher stellt die Beschreibung die Fähigkeiten des Codes deutlich breiter dar als tatsächlich implementiert.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
Die deklarierte Beschreibung nennt eine Buchhaltungsautomatisierung mit EÜR-Erstellung, DATEV-Export, PDF-Beleganalyse und Steuer-Vorbereitung. Der vorliegende Code implementiert jedoch ausschließlich einen Rechnungsgenerator, der mit FPDF Rechnungen als PDF erstellt und lokal speichert. Es gibt keine Logik für Einnahmen-Überschuss-Rechnung, keinen DATEV-Datenexport, keine Analyse eingehender PDF-Belege und keine weitergehende Steueraufbereitung. Damit weicht der tatsächliche Hauptzweck wesentlich von der beschriebenen Funktion ab.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
Die deklarierte Beschreibung verspricht eine Buchhaltungs- und Steuerautomatisierung mit mehreren spezifischen Funktionen (EÜR, DATEV-Export, Beleganalyse, Steuer-Vorbereitung). Der vorliegende Code implementiert jedoch ausschließlich einen Rechnungs-Generator, der PDF-Rechnungen erstellt und lokal speichert. Es gibt keine Logik zur Buchhaltung, keine Auswertung von Belegen, keinen DATEV-Export und keine EÜR-Erstellung. Der enthaltene UStG-Hinweis ist nur ein statischer Rechnungstext und keine echte Steuer-Vorbereitung. Damit weicht der tatsächliche Primärzweck wesentlich von der Beschreibung ab.

Lp3

Medium
Category
MCP Least Privilege
Confidence
86% confidence
Finding
The skill advertises shell, file read, and file write style usage through example commands, but does not declare any explicit tool scope such as permissions or allowed-tools. This creates an unnecessary trust gap: consumers and enforcement layers cannot tell what filesystem or command execution access the skill expects, which increases the risk of over-privileged execution in a finance-focused context handling sensitive accounting data.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The skill is explicitly positioned to process invoices, accounting records, and DATEV-style exports, which commonly contain personal, banking, tax, and business-sensitive information. Failing to warn users about this data sensitivity and the handling expectations can lead to unsafe use, oversharing, insecure storage, or accidental disclosure in environments that are not appropriate for regulated financial documents.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
"""Extrahiert Daten aus einer Rechnungs-PDF"""
    
    # PDF zu Text
    result = subprocess.run(
        ['pdftotext', '-layout', pdf_path, '-'],
        capture_output=True, text=True
    )
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Context-Inappropriate Capability

Medium
Confidence
84% confidence
Finding
The manifest and module/docstrings describe PDF receipt/invoice analysis and data extraction, but the implementation shells out to the external `pdftotext` binary using `subprocess.run`. Spawning external processes is a broader capability than simple document parsing and is not declared or justified by the stated business purpose in the provided manifest/context.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The function includes `text_preview` derived from invoice contents in its returned data, which is later printed to stdout. Invoice text can contain personal, financial, tax, and account data, so emitting even partial content without redaction or explicit consent can expose sensitive information through terminals, logs, CI output, or downstream tooling.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
During folder analysis, the script prints full analysis details as JSON, including absolute or relative file paths and invoice metadata for every document. This can disclose sensitive business structure, supplier relationships, dates, and amounts to anyone with access to console history or logs, which is especially risky in accounting workflows handling confidential records.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The save() method writes generated accounting/tax data to whatever output_path is provided, with no validation, path restrictions, or overwrite protection. In an agent context, an attacker or unsafe prompt flow could steer the skill into overwriting arbitrary files accessible to the process or writing sensitive financial data to unintended locations, causing integrity loss or disclosure.

Natural-Language Policy Violations

Low
Confidence
88% confidence
Finding
The natural-language content and examples are presented only in German, which can constitute a language policy issue when no user opt-in or explicit locale limitation is provided. There is no statement that the skill is intended specifically for German-speaking users or German accounting contexts only.

Natural-Language Policy Violations

Low
Confidence
95% confidence
Finding
The skill’s natural-language description and inline user-facing text are entirely in German, which can amount to a language/locale constraint without explicit user opt-in. The file does not document that the skill is intentionally limited to German-speaking or German accounting contexts, nor does it offer a language choice.

Intent-Code Divergence

Low
Confidence
98% confidence
Finding
The function is named `from_buchhaltungs_json`, takes `json_path`, and its docstring describes creating an export from bookkeeping data, implying JSON input. However, the code opens the file with `csv.DictReader` and reads comma-delimited rows, which directly contradicts the stated input format.

Natural-Language Policy Violations

Low
Confidence
77% confidence
Finding
Natural-language strings, comments, and generated document text are consistently German-only, which can amount to forcing a specific language without user opt-in. There is no indication that the skill is intentionally limited to German-language users or German regulatory use cases.

Missing User Warnings

Low
Confidence
83% confidence
Finding
This code creates a directory and writes a PDF file to the filesystem, which is a file-modifying operation. Although the script prints success messages in the example main block, the reusable create_rechnung function itself provides no prompt, warning, or explicit disclosure before performing the write.

Static analysis

No suspicious patterns detected.