T09 · Insecure Skill Coding Practices
- 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. ]]>
