Back to skill

Security audit

Rapprochement Bancaire

Security checks for vulnerabilities and agentic risk

Overview

The skill is mostly a disclosed local accounting reconciler, but its matching code can incorrectly mark invoices as paid, so it needs review before use.

Install only for a French accounting workflow and run it on a test copy or reviewed client root first. Do not rely on its paid/unpaid results for closing, reminders, or client decisions until the matching bugs are fixed and a human accountant has reviewed the generated JSON reports.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/main.py:219
Finding

Payment reconciliation does not enforce transaction direction

Content
View full analysis
) for inv in invoices.values(): for tx in transactions: if tx.get("invoice_ref") and tx["invoice_ref"] == inv["invoice_id"]: paid = round(abs(tx["amount"]), 2) if abs(paid - inv["amount"]) <= 1.0: inv["status"] = "paid" elif paid < inv["amount"]: inv["status"] = "partial" inv["amount_paid"] = paid inv["amount_remaining"] = round(inv["amount"] - paid, 2) else: inv["status"] = "paid" inv["amount_paid"] = paid inv["overpaid_by"] = round(paid - inv["amount"], 2) inv["bank_matched"] = True inv["matched_tx"] = tx["raw_label"] break # Pass 2 — fuzzy : |montant| ±1€ + similarité libellé / contrepartie ≥ 0.6 for inv in invoices.values(): if inv["bank_matched"]: continue for tx in transactions: if abs(abs(tx["amount"]) - inv["amount"]) > 1.0: continue if similarity(tx["label"], inv.get("counterparty_name", "")) >= 0.6: inv["status"] = "paid" inv["bank_matched"] = True inv["matched_tx"] = tx["raw_label"] break ``` ### Technical Analysis The reconciliation engine records invoice direction in the `type` field: an outgoing invoice (`out`) should be settled only by a positive bank credit, while an incoming invoice (`in`) should be settled only by a negative bank debit. Both reconciliation passes discard the transaction sign using `abs(tx["amount"])`. Neither pass compares the transaction direction with `inv["type"]`. Consequently: - A debit can mark an outgoing sales i ...[truncated 1842 chars]
Remediation
View remediation
0 if invoice["type"] == "in": return amount < 0 return False ``` 2. Invoke this check before reference, amount, or fuzzy-label comparisons: ```python if not has_valid_direction(inv, tx): continue ``` 3. Avoid normalizing the sign until after direction validation. Use `abs()` only to compare magnitudes. 4. Add regression tests covering: - outgoing invoice plus credit: accepted; - outgoing invoice plus debit: rejected; - incoming invoice plus debit: accepted; - incoming invoice plus credit: rejected; - both direct-reference and fuzzy matching paths. 5. Record rejected opposite-direction candidates as reviewable anomalies when they otherwise strongly match an invoice. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/main.py:219
Finding

A single bank transaction can settle multiple invoices

Content
View full analysis
) for inv in invoices.values(): for tx in transactions: if tx.get("invoice_ref") and tx["invoice_ref"] == inv["invoice_id"]: paid = round(abs(tx["amount"]), 2) if abs(paid - inv["amount"]) <= 1.0: inv["status"] = "paid" elif paid < inv["amount"]: inv["status"] = "partial" inv["amount_paid"] = paid inv["amount_remaining"] = round(inv["amount"] - paid, 2) else: inv["status"] = "paid" inv["amount_paid"] = paid inv["overpaid_by"] = round(paid - inv["amount"], 2) inv["bank_matched"] = True inv["matched_tx"] = tx["raw_label"] break # Pass 2 — fuzzy : |montant| ±1€ + similarité libellé / contrepartie ≥ 0.6 for inv in invoices.values(): if inv["bank_matched"]: continue for tx in transactions: if abs(abs(tx["amount"]) - inv["amount"]) > 1.0: continue if similarity(tx["label"], inv.get("counterparty_name", "")) >= 0.6: inv["status"] = "paid" inv["bank_matched"] = True inv["matched_tx"] = tx["raw_label"] break ``` ### Technical Analysis The loops operate invoice-by-invoice, but no transaction is marked as consumed after a successful match. Every subsequent invoice iterates over the complete transaction list again. This permits one transaction to be reused for multiple invoices. Direct-reference reuse can occur when multiple invoice files resolve to the same extracted invoice ID. Fuzzy reuse can occur when multiple invoices have the same or similar counterparty and amounts within the €1 toler ...[truncated 1693 chars]
Remediation
View remediation
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • 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 (27)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The description frames the skill as a daily accounting engine that works on already-classified client files, reconciles payments with invoices, validates VAT, and updates tracking JSON files, while explicitly stating it never classifies documents. The supplied code chunk instead is a low-level PDF text extraction and document classification/parser module. It determines whether a PDF is an invoice or bank statement and extracts structured accounting fields from the document. That means it does perform document classification, which the description explicitly says the skill never does. Also, the primary behavior in this chunk is extraction/parsing, not reconciliation or JSON state maintenance. While the description mentions scripts/main.py calls scripts/extract.py, and this extractor could be a supporting component of the larger skill, the explicit claim 'Ne traite jamais les e-mails, ne classe jamais de documents' conflicts with the observed classification logic in this code. Therefore this is a material description-behavior mismatch.

Content

No source excerpt is available for this finding.

Hidden Instructions

High
Category
Prompt Injection
Confidence
60% confidence
Finding

Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Content

Scanner excerpt · references/csv-schema.md (reported line 19)May include surrounding context.

md
## Encodage et locale

- **Encoding** : UTF-8 avec BOM (`` en tête) — pour Excel français qui sinon mojibake.
- **Séparateur** : `;` (semicolon) — convention française, évite la confusion avec décimales `,`.
- **Décimal** : `,` (virgule).
- **Date** : `AAAA-MM-JJ` (ISO 8601, lisible par tout tableur).

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding

The skill instructs the agent to execute a shell command and read/write accounting artifacts, but it does not declare any explicit tool scope or permissions boundaries. That creates an unnecessary trust gap: an orchestrator or reviewer cannot enforce that the skill is limited to the intended client tree, increasing the risk of unintended command execution or filesystem access if the skill or called scripts are modified.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The 'Encodage et locale' section explicitly requires French Excel compatibility, French separator conventions, and comma decimals. This is a natural-language locale policy constraint presented as mandatory behavior, with no indication that users can choose another locale or that the skill is limited to a justified France-specific deployment context.

Content

No source excerpt is available for this finding.

Whitespace Padding

Medium
Category
Prompt Injection
Confidence
70% confidence
Finding

Large whitespace padding was detected (a block of blank lines or a long run of spaces). This can push injected instructions below or to the right of the visible area so a human reviewer never sees them while the agent still reads them. Manual review of the hidden content is recommended.

Content

Scanner excerpt · references/csv-schema.md (reported line 30)May include surrounding context.

md
## Colonnes du CSV

| #  | Colonne                | Type          | Description                                                                                  |
| -- | ---------------------- | ------------- | -------------------------------------------------------------------------------------------- |
| 1  | `ligne`                | int           | Numéro de ligne séquentiel (1, 2, 3, …) — facilite la référence dans les conversations       |
| 2  | `source`               | enum          | `transaction` (ligne de relevé), `facture_non_payee` (facture sans transaction)              |

Whitespace Padding

Medium
Category
Prompt Injection
Confidence
70% confidence
Finding

Large whitespace padding was detected (a block of blank lines or a long run of spaces). This can push injected instructions below or to the right of the visible area so a human reviewer never sees them while the agent still reads them. Manual review of the hidden content is recommended.

Content

Scanner excerpt · references/matching-rules.md (reported line 159)May include surrounding context.

md
## Colonnes du CSV

| #  | Colonne                | Type          | Description                                                                                  |
| -- | ---------------------- | ------------- | -------------------------------------------------------------------------------------------- |
| 1  | `ligne`                | int           | Numéro de ligne séquentiel (1, 2, 3, …) — facilite la référence dans les conversations       |
| 2  | `source`               | enum          | `transaction` (ligne de relevé), `facture_non_payee` (facture sans transaction)              |

Whitespace Padding

Medium
Category
Prompt Injection
Confidence
70% confidence
Finding

Large whitespace padding was detected (a block of blank lines or a long run of spaces). This can push injected instructions below or to the right of the visible area so a human reviewer never sees them while the agent still reads them. Manual review of the hidden content is recommended.

Content

Scanner excerpt · references/structure-cible.md (reported line 238)May include surrounding context.

md
## Colonnes du CSV

| #  | Colonne                | Type          | Description                                                                                  |
| -- | ---------------------- | ------------- | -------------------------------------------------------------------------------------------- |
| 1  | `ligne`                | int           | Numéro de ligne séquentiel (1, 2, 3, …) — facilite la référence dans les conversations       |
| 2  | `source`               | enum          | `transaction` (ligne de relevé), `facture_non_payee` (facture sans transaction)              |

Whitespace Padding

Medium
Category
Prompt Injection
Confidence
70% confidence
Finding

Large whitespace padding was detected (a block of blank lines or a long run of spaces). This can push injected instructions below or to the right of the visible area so a human reviewer never sees them while the agent still reads them. Manual review of the hidden content is recommended.

Content

Scanner excerpt · references/csv-schema.md (reported line 55)May include surrounding context.

md
| Valeur                      | Sens                                                                                                |
| --------------------------- | --------------------------------------------------------------------------------------------------- |
| (vide)                      | Aucune anomalie                                                                                     |
| `paiement_orphelin`         | Transaction débit sans facture in correspondante                                                    |
| `encaissement_sans_facture` | Transaction crédit sans facture out correspondante                                                  |
| `facture_non_payee`         | Facture out avec échéance dépassée et pas de paiement détecté                                       |

Whitespace Padding

Medium
Category
Prompt Injection
Confidence
70% confidence
Finding

Large whitespace padding was detected (a block of blank lines or a long run of spaces). This can push injected instructions below or to the right of the visible area so a human reviewer never sees them while the agent still reads them. Manual review of the hidden content is recommended.

Content

Scanner excerpt · references/csv-schema.md (reported line 53)May include surrounding context.

md
### Côté transaction (extraite du relevé)

| Champ                | Normalisation                                                                                                |
| -------------------- | ------------------------------------------------------------------------------------------------------------ |
| `montant`            | Décimal, signé (`+` crédit, `-` débit), arrondi 0,01 €                                                       |
| `date`               | ISO 8601 (`YYYY-MM-DD`)                                                                                       |

Whitespace Padding

Medium
Category
Prompt Injection
Confidence
70% confidence
Finding

Large whitespace padding was detected (a block of blank lines or a long run of spaces). This can push injected instructions below or to the right of the visible area so a human reviewer never sees them while the agent still reads them. Manual review of the hidden content is recommended.

Content

Scanner excerpt · references/matching-rules.md (reported line 11)May include surrounding context.

md
### Côté transaction (extraite du relevé)

| Champ                | Normalisation                                                                                                |
| -------------------- | ------------------------------------------------------------------------------------------------------------ |
| `montant`            | Décimal, signé (`+` crédit, `-` débit), arrondi 0,01 €                                                       |
| `date`               | ISO 8601 (`YYYY-MM-DD`)                                                                                       |

Whitespace Padding

Medium
Category
Prompt Injection
Confidence
70% confidence
Finding

Large whitespace padding was detected (a block of blank lines or a long run of spaces). This can push injected instructions below or to the right of the visible area so a human reviewer never sees them while the agent still reads them. Manual review of the hidden content is recommended.

Content

Scanner excerpt · README.md (reported line 43)May include surrounding context.

md
| Champ                | Normalisation                                                                                                |
| -------------------- | ------------------------------------------------------------------------------------------------------------ |
| `montant`            | Décimal, signé (`+` crédit, `-` débit), arrondi 0,01 €                                                       |
| `date`               | ISO 8601 (`YYYY-MM-DD`)                                                                                       |
| `libelle`            | Trim, espaces multiples → simple espace, lowercase                                                            |
| `libelle_tokens`     | `libelle` splitté par espaces / ponctuation, tokens ≥ 3 caractères, sans stop-words bancaires (`vir`, `prlv`, `cb`, `chq`, `faveur`, `de`, `du`, `de la`) |

Whitespace Padding

Medium
Category
Prompt Injection
Confidence
70% confidence
Finding

Large whitespace padding was detected (a block of blank lines or a long run of spaces). This can push injected instructions below or to the right of the visible area so a human reviewer never sees them while the agent still reads them. Manual review of the hidden content is recommended.

Content

Scanner excerpt · README.md (reported line 52)May include surrounding context.

md
| Champ                | Normalisation                                                                                                |
| -------------------- | ------------------------------------------------------------------------------------------------------------ |
| `montant`            | Décimal, signé (`+` crédit, `-` débit), arrondi 0,01 €                                                       |
| `date`               | ISO 8601 (`YYYY-MM-DD`)                                                                                       |
| `libelle`            | Trim, espaces multiples → simple espace, lowercase                                                            |
| `libelle_tokens`     | `libelle` splitté par espaces / ponctuation, tokens ≥ 3 caractères, sans stop-words bancaires (`vir`, `prlv`, `cb`, `chq`, `faveur`, `de`, `du`, `de la`) |

Whitespace Padding

Medium
Category
Prompt Injection
Confidence
70% confidence
Finding

Large whitespace padding was detected (a block of blank lines or a long run of spaces). This can push injected instructions below or to the right of the visible area so a human reviewer never sees them while the agent still reads them. Manual review of the hidden content is recommended.

Content

Scanner excerpt · references/matching-rules.md (reported line 14)May include surrounding context.

md
| Champ                | Normalisation                                                                                                |
| -------------------- | ------------------------------------------------------------------------------------------------------------ |
| `montant`            | Décimal, signé (`+` crédit, `-` débit), arrondi 0,01 €                                                       |
| `date`               | ISO 8601 (`YYYY-MM-DD`)                                                                                       |
| `libelle`            | Trim, espaces multiples → simple espace, lowercase                                                            |
| `libelle_tokens`     | `libelle` splitté par espaces / ponctuation, tokens ≥ 3 caractères, sans stop-words bancaires (`vir`, `prlv`, `cb`, `chq`, `faveur`, `de`, `du`, `de la`) |

Whitespace Padding

Medium
Category
Prompt Injection
Confidence
70% confidence
Finding

Large whitespace padding was detected (a block of blank lines or a long run of spaces). This can push injected instructions below or to the right of the visible area so a human reviewer never sees them while the agent still reads them. Manual review of the hidden content is recommended.

Content

Scanner excerpt · references/matching-rules.md (reported line 23)May include surrounding context.

md
| Champ                | Normalisation                                                                              |
| -------------------- | ------------------------------------------------------------------------------------------ |
| `montantTTC`         | Décimal positif (le sens vient du `categorie`: `achat` = débit, `vente` = crédit)         |
| `dateEmission`       | ISO 8601                                                                                   |
| `emetteur_normalise` | lowercase, accents retirés, suffixes juridiques retirés (`SA`, `SAS`, `SARL`, `EURL`, `Ltd`) |
| `numeroFacture`      | Conservé tel quel + variante numérique pure (`F-2026-04-1287` → aussi `20260412 87`)      |

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

Ce fichier markdown indique qu'un match de confiance fort ou moyen entraîne un update de followup.md. Comme il s'agit d'une modification de données utilisateur, la description devrait avertir explicitement que le skill écrira dans ce fichier afin d'éviter une surprise ou une altération non anticipée.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

This markdown file describes behavior that physically moves files into client directories and removes corresponding entries from pending-attribution.json. Because these are user-data-affecting operations, the skill description should clearly warn users that documents and metadata will be automatically relocated and modified as part of processing.

Content

No source excerpt is available for this finding.

Whitespace Padding

Medium
Category
Prompt Injection
Confidence
70% confidence
Finding

Large whitespace padding was detected (a block of blank lines or a long run of spaces). This can push injected instructions below or to the right of the visible area so a human reviewer never sees them while the agent still reads them. Manual review of the hidden content is recommended.

Content

Scanner excerpt · references/structure-cible.md (reported line 86)May include surrounding context.

md
### Composants de nom de fichier

| Token            | Règle                                                                                                  |
| ---------------- | ------------------------------------------------------------------------------------------------------ |
| `AAAA-MM-JJ`     | `dateEmission` du document (ISO 8601), pas date de réception                                          |
| `AAAA-MM`        | `dateEmission` tronquée au mois — utilisé pour les relevés bancaires (couvre généralement un mois)    |

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

These lines describe corrective reclassification that moves files, updates multiple index.json files, and writes to audit.log. In markdown-scoped review, such system-integrity-affecting behavior should be disclosed with a clear warning so users understand that running the skill can alter existing records.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/extract.py (reported line 44)May include surrounding context.

python
def pdftext(path):
    try:
        r = subprocess.run(["pdftotext", "-layout", str(path), "-"],
                           capture_output=True, text=True, errors="ignore", timeout=30)
        return r.stdout
    except Exception:

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

Ce fichier Python effectue des écritures sur disque de followup.json, relances.json et anomalies.json, qui agrègent des informations financières et potentiellement sensibles par client. Bien que la docstring décrive globalement ce comportement, le code ne fournit ni confirmation, ni journal utilisateur au moment de ces écritures par client, ce qui correspond à une opération de modification de fichiers sans divulgation visible dans l'exécution.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
92% confidence
Finding

This markdown file describes that the skill runs a command and writes per-client JSON outputs plus a consolidated report, but it presents those writes as behavior rather than an explicit caution to the user. Because the skill modifies files in multiple locations, the README should clearly warn users about this side effect before invocation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

Tout le contenu opérationnel et les libellés attendus sont rédigés en français, sans mention d'opt-in linguistique ni justification de contrainte régionale. Selon la règle de politique linguistique, forcer une langue spécifique sans choix explicite peut constituer une violation de politique naturelle.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
82% confidence
Finding

Les actions de classification indiquent qu'une Ligne CSV est écrite ou annotée selon le score, mais le document ne formule pas explicitement d'avertissement utilisateur sur cette écriture de fichier. Pour un skill manipulant des données comptables, une mention claire des sorties générées aide à préserver l'intégrité et la prévisibilité des traitements.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
81% confidence
Finding

A language policy issue can arise when a skill's instructions and expected interactions are fixed to a single language without offering the user a choice. This file consistently uses French and does not state that French is optional or that other languages are supported.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

The natural-language documentation and labels in the file are predominantly French, which can impose a language expectation on users or maintainers without opt-in. The file does not state that the skill is intentionally restricted to a French-language accounting domain or offer any language/locale choice.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.