---
title: "GHSA-mrrj-6m2q-jch9"
description: "ISO 20022 business rules read a different amount and currency than the parsed XML, allowing over-limit and disallowed-currency payments to pass. Affected and fixed versions of qwed-finance."
url: https://qwedai.com/security/advisories/ghsa-mrrj-6m2q-jch9
---

# GHSA-mrrj-6m2q-jch9

ISO 20022 business rules read a different amount and currency than the parsed XML, allowing over-limit and disallowed-currency payments to pass

### Impact

The ISO 20022 business-rules engine in `qwed-finance` (`CrossGuard.verify_iso20022_with_rules`, also used by `UCPIntegration.verify_iso20022_payment`) extracts the settlement amount and currency from the raw XML text with a regular expression, instead of from the parsed XML tree that `MessageGuard` validates. An XML document can therefore show one amount and currency to the rules engine while every XML parser — and any downstream payment system — reads another.

Two constructs make the rules engine read a decoy:

-   the operative element uses a namespace prefix containing a character that is a valid XML NameChar but outside the regex prefix class `[\w.-]` (for example `U+00B7`), so the regex never sees it;
-   a decoy amount element is placed inside an XML processing instruction (`<?...?>`); comments and CDATA are stripped before matching, but processing instructions are not.

Reproduced on v3.0.0 with business rules `max_amount=1000`, `allowed_currencies=["USD"]`:

| Document | Parsers read | Rules engine result |
| --- | --- | --- |
| plain `IntrBkSttlmAmt Ccy="RUB"` 9,999,999.00 | RUB 9,999,999.00 | rejected (both rules) |
| same amount behind a prefixed element plus a PI decoy `USD 100.00` | RUB 9,999,999.00 | **`passed=True`, no violations** |

Through `UCPIntegration(max_transaction_amount=1000, allowed_currencies=["USD"]).verify_iso20022_payment(...)` the same document returns **`PaymentStatus.APPROVED`, `can_proceed=True`** .

**Who is affected:** applications that rely on `verify_iso20022_with_rules` or `UCPIntegration.verify_iso20022_payment` to enforce amount limits or currency allow-lists on ISO 20022 (pacs.008) messages produced by an LLM or another untrusted source. The npm SDK does not expose these code paths.

### Root cause

`cross_guard.py` (`_AMOUNT_ELEMENT_RE`, `_extract_xml_occurrences`) performs regex extraction over raw document text. Earlier fixes (comment/CDATA stripping, all-occurrence matching, `\w` prefixes) narrowed the gap but kept a second, regex-based view of the document that can disagree with the XML tree.

### Patches

Fixed in **qwed-finance 3.0.1** ([release](https://github.com/QWED-AI/qwed-finance/releases/tag/v3.0.1)). Upgrade with `pip install -U qwed-finance==3.0.1`.

The business-rules engine now takes `IntrBkSttlmAmt` amounts and `Ccy` currencies from the defusedxml-parsed XML tree (matched by local name in any namespace), not from a regular expression over raw text. In addition:

-   an amount element containing child nodes (elements, comments, processing instructions) fails closed as unparseable;
-   amounts must be a plain `xs:decimal` — exponents and grouping separators are rejected;
-   character references are decoded exactly once, by the parser.

### Workarounds

-   Extract the amount and currency yourself from the parsed XML tree (by namespace-qualified local name) and enforce limits on those values; do not rely on `verify_iso20022_with_rules` for limit enforcement.
-   Reject documents that contain processing instructions or non-default namespace prefixes on amount elements before verification.

### References

Reproduced on `qwed-finance` 3.0.0 (`bb0cdf3`).
