CVE-2026-107841
pacioli: A submit consent marker licensed cancellation of caller-named pre-existing documents
pacioli provides least-privilege governance and a governed agent broker for ERPNext. From version 0.9.6 until version 0.10.0, the pacioli-guard document-layer consent gate allows nested cancellation operations to ride any consent established by an enclosing governed act without checking whether the marker authorizes cancellation. A credential with API Key Scope.require_consent can submit a caller-controlled Sales Invoice or other supported document under a valid human-minted submit marker and reach Document.cancel() for a different pre-existing submitted document, bypassing the marker's document and act binding, single-use spend, and denial audit. The unauthorized cancellation can reverse the target document's ledger effect; principals without a consent-gated grant are not affected. This issue is fixed in version 0.10.0.
Attack profile
How easy it is to exploit
- Attack vector
- Network
- Complexity
- Low
- Privileges needed
- Low
- User interaction
- Required
What an attacker can affect
- Confidentiality
- None
- Integrity
- High
- Availability
- None
Exploit likelihood
What each source reports
CVE List Score used
5.7
pacioli: A submit consent marker licensed cancellation of caller-named pre-existing documents
pacioli provides least-privilege governance and a governed agent broker for ERPNext. From version 0.9.6 until version 0.10.0, the pacioli-guard document-layer consent gate allows nested cancellation operations to ride any consent established by an enclosing governed act without checking whether the marker authorizes cancellation. A credential with API Key Scope.require_consent can submit a caller-controlled Sales Invoice or other supported document under a valid human-minted submit marker and reach Document.cancel() for a different pre-existing submitted document, bypassing the marker's document and act binding, single-use spend, and denial audit. The unauthorized cancellation can reverse the target document's ledger effect; principals without a consent-gated grant are not affected. This issue is fixed in version 0.10.0.
- Record
CVE-2026-107841- CVSS 3.1
- 5.7 Medium
CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:N/I:H/A:N - Weakness
- CWE-863
- Updated
- 2026-11-02
EUVDEUVD-2026-95937
5.7
pacioli provides least-privilege governance and a governed agent broker for ERPNext. From version 0.9.6 until version 0.10.0, the pacioli-guard document-layer consent gate allows nested cancellation operations to ride any consent established by an enclosing governed act without checking whether the marker authorizes cancellation. A credential with API Key Scope.require_consent can submit a caller-controlled Sales Invoice or other supported document under a valid human-minted submit marker and reach Document.cancel() for a different pre-existing submitted document, bypassing the marker's document and act binding, single-use spend, and denial audit. The unauthorized cancellation can reverse the target document's ledger effect; principals without a consent-gated grant are not affected. This issue is fixed in version 0.10.0.
- Record
EUVD-2026-95937- CVSS 3.1
- 5.7 Medium
CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:N/I:H/A:N - Updated
- 2026-11-02
GitHub AdvisoriesGHSA-3hj7-6vmj-h8v4
5.7
pacioli: A submit consent marker licensed cancellation of caller-named pre-existing documents
Impact
pacioli-guard's document-layer consent gate requires a human-minted, single-use, document-bound and act-bound marker before a credential carrying API Key Scope.require_consent may submit or cancel a document. Because ERPNext performs further document writes as a consequence of a governed act, nested acts are allowed to "ride" the consent established by the enclosing act instead of needing a marker of their own.
The ride predicate returned true for every cancel, regardless of which act the enclosing marker authorised. Riding never reaches consent_verdict, which is where the marker-to-act binding is enforced. The result: any Document.cancel() performed inside an act that had established consent reached docstatus = 2 with no marker, no act-binding check, no single-use spend, and no denial audit row.
This is reachable with the exact grant an operator is documented to give the broker, and the cancelled document's identity is caller-controlled:
Sales Invoice.on_submit(sales_invoice.py:507) callsprocess_asset_depreciation()unconditionally, reachingdepreciate_asset_on_sale(:1508-1516).- That iterates the invoice's item rows and calls
frappe.get_doc("Asset", d.asset).Sales Invoice Item.assetis a plain writableLinkwith noread_onlyand nofetch_from, so the caller supplies it in the request body. The validation that would constrain it sits behindif d.is_fixed_asset:(:428-429), a server-set field. - The chain reaches
depreciation.py:481and thenasset_depreciation_schedule.py:215-217, which callscurrent_schedule.cancel()on adocstatus == 1, submittableAsset Depreciation Schedulethrough the document lifecycle (onlyshould_not_cancel_depreciation_entriesis set, notignore_validate, sobefore_canceldoes fire and the ride is what admitted it).
So one marker authorising submit Sales Invoice X cancelled a submitted document the human was never shown and never approved. Cancelling such a document reverses its ledger effect.
The same shape exists behind wider grants, for example Unreconcile Payment.on_submit (unreconcile_payment.py:59-64), which walks a child table the caller fills and reaches accounts/utils.py:857/:859 gain_loss_je.cancel() on submitted Journal Entries.
Who is affected
Only sites that had opted into consent gating: a credential must hold an API Key Scope with require_consent set. pacioli-guard is inert for principals without such a grant, and the credential-scoping floor (auth_hooks) is unaffected by this issue.
The document-layer consent gate was first published in 0.9.6, which is the only released version in the affected range.
Patches
Fixed in 0.10.0. The ride now discriminates on the enclosing act: an undo may cascade into further undos, but a submit may not cascade into the cancellation of a document that already has a name, because that is an act a human could have been asked to approve. The custody stamp carries the act it was established for rather than a bare boolean, which is the state the vulnerable code lacked.
Upgrading changes behavior. Any ERPNext flow where a submit cascades into a lifecycle cancel now requires a consent marker for that cancel as well as for the act itself. In ERPNext v16 that includes asset sale, partial-quantity asset sale, a credit note against an asset sale, Asset Repair capitalization, Asset Shift Allocation, Asset Value Adjustment, and Unreconcile Payment. To make that possible, the X-Pacioli-Consent header now accepts several markers separated by whitespace or commas; each remains bound to one document and one act, requires a different minter, and is spent exactly once.
Workarounds
On 0.9.6, remove require_consent from affected grants and rely on the credential-scoping floor alone, or scope governed credentials so they cannot submit documents whose controllers cancel other documents (for ERPNext slice-one, Sales Invoice with…
- Record
GHSA-3hj7-6vmj-h8v4- CVSS 3.1
- 5.7 Medium
CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:N/I:H/A:N - Weakness
- CWE-863
- Updated
- 2026-11-02
NVD
5.7
pacioli provides least-privilege governance and a governed agent broker for ERPNext. From version 0.9.6 until version 0.10.0, the pacioli-guard document-layer consent gate allows nested cancellation operations to ride any consent established by an enclosing governed act without checking whether the marker authorizes cancellation. A credential with API Key Scope.require_consent can submit a caller-controlled Sales Invoice or other supported document under a valid human-minted submit marker and reach Document.cancel() for a different pre-existing submitted document, bypassing the marker's document and act binding, single-use spend, and denial audit. The unauthorized cancellation can reverse the target document's ledger effect; principals without a consent-gated grant are not affected. This issue is fixed in version 0.10.0.
- Record
CVE-2026-107841- CVSS 3.1
- 5.7 Medium
CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:N/I:H/A:N - Weakness
- CWE-863
- Updated
- 2026-11-02
OSV
5.7
pacioli: A submit consent marker licensed cancellation of caller-named pre-existing documents
pacioli provides least-privilege governance and a governed agent broker for ERPNext. From version 0.9.6 until version 0.10.0, the pacioli-guard document-layer consent gate allows nested cancellation operations to ride any consent established by an enclosing governed act without checking whether the marker authorizes cancellation. A credential with API Key Scope.require_consent can submit a caller-controlled Sales Invoice or other supported document under a valid human-minted submit marker and reach Document.cancel() for a different pre-existing submitted document, bypassing the marker's document and act binding, single-use spend, and denial audit. The unauthorized cancellation can reverse the target document's ledger effect; principals without a consent-gated grant are not affected. This issue is fixed in version 0.10.0.
- Record
CVE-2026-107841- CVSS 3.1
- 5.7 Medium
CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:N/I:H/A:N - Weakness
- CWE-863
- Updated
- 2026-11-02
OSVGHSA-3hj7-6vmj-h8v4
5.7
pacioli: A submit consent marker licensed cancellation of caller-named pre-existing documents
Impact
pacioli-guard's document-layer consent gate requires a human-minted, single-use, document-bound and act-bound marker before a credential carrying API Key Scope.require_consent may submit or cancel a document. Because ERPNext performs further document writes as a consequence of a governed act, nested acts are allowed to "ride" the consent established by the enclosing act instead of needing a marker of their own.
The ride predicate returned true for every cancel, regardless of which act the enclosing marker authorised. Riding never reaches consent_verdict, which is where the marker-to-act binding is enforced. The result: any Document.cancel() performed inside an act that had established consent reached docstatus = 2 with no marker, no act-binding check, no single-use spend, and no denial audit row.
This is reachable with the exact grant an operator is documented to give the broker, and the cancelled document's identity is caller-controlled:
Sales Invoice.on_submit(sales_invoice.py:507) callsprocess_asset_depreciation()unconditionally, reachingdepreciate_asset_on_sale(:1508-1516).- That iterates the invoice's item rows and calls
frappe.get_doc("Asset", d.asset).Sales Invoice Item.assetis a plain writableLinkwith noread_onlyand nofetch_from, so the caller supplies it in the request body. The validation that would constrain it sits behindif d.is_fixed_asset:(:428-429), a server-set field. - The chain reaches
depreciation.py:481and thenasset_depreciation_schedule.py:215-217, which callscurrent_schedule.cancel()on adocstatus == 1, submittableAsset Depreciation Schedulethrough the document lifecycle (onlyshould_not_cancel_depreciation_entriesis set, notignore_validate, sobefore_canceldoes fire and the ride is what admitted it).
So one marker authorising submit Sales Invoice X cancelled a submitted document the human was never shown and never approved. Cancelling such a document reverses its ledger effect.
The same shape exists behind wider grants, for example Unreconcile Payment.on_submit (unreconcile_payment.py:59-64), which walks a child table the caller fills and reaches accounts/utils.py:857/:859 gain_loss_je.cancel() on submitted Journal Entries.
Who is affected
Only sites that had opted into consent gating: a credential must hold an API Key Scope with require_consent set. pacioli-guard is inert for principals without such a grant, and the credential-scoping floor (auth_hooks) is unaffected by this issue.
The document-layer consent gate was first published in 0.9.6, which is the only released version in the affected range.
Patches
Fixed in 0.10.0. The ride now discriminates on the enclosing act: an undo may cascade into further undos, but a submit may not cascade into the cancellation of a document that already has a name, because that is an act a human could have been asked to approve. The custody stamp carries the act it was established for rather than a bare boolean, which is the state the vulnerable code lacked.
Upgrading changes behavior. Any ERPNext flow where a submit cascades into a lifecycle cancel now requires a consent marker for that cancel as well as for the act itself. In ERPNext v16 that includes asset sale, partial-quantity asset sale, a credit note against an asset sale, Asset Repair capitalization, Asset Shift Allocation, Asset Value Adjustment, and Unreconcile Payment. To make that possible, the X-Pacioli-Consent header now accepts several markers separated by whitespace or commas; each remains bound to one document and one act, requires a different minter, and is spent exactly once.
Workarounds
On 0.9.6, remove require_consent from affected grants and rely on the credential-scoping floor alone, or scope governed credentials so they cannot submit documents whose controllers cancel other documents (for ERPNext slice-one, Sales Invoice with…
- Record
GHSA-3hj7-6vmj-h8v4- CVSS 3.1
- 5.7 Medium
CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:N/I:H/A:N - Weakness
- CWE-863
- Updated
- 2026-11-02
OSVPYSEC-2026-4246
5.7
pacioli: A submit consent marker licensed cancellation of caller-named pre-existing documents
Impact
pacioli-guard's document-layer consent gate requires a human-minted, single-use, document-bound and act-bound marker before a credential carrying API Key Scope.require_consent may submit or cancel a document. Because ERPNext performs further document writes as a consequence of a governed act, nested acts are allowed to "ride" the consent established by the enclosing act instead of needing a marker of their own.
The ride predicate returned true for every cancel, regardless of which act the enclosing marker authorised. Riding never reaches consent_verdict, which is where the marker-to-act binding is enforced. The result: any Document.cancel() performed inside an act that had established consent reached docstatus = 2 with no marker, no act-binding check, no single-use spend, and no denial audit row.
This is reachable with the exact grant an operator is documented to give the broker, and the cancelled document's identity is caller-controlled:
Sales Invoice.on_submit(sales_invoice.py:507) callsprocess_asset_depreciation()unconditionally, reachingdepreciate_asset_on_sale(:1508-1516).- That iterates the invoice's item rows and calls
frappe.get_doc("Asset", d.asset).Sales Invoice Item.assetis a plain writableLinkwith noread_onlyand nofetch_from, so the caller supplies it in the request body. The validation that would constrain it sits behindif d.is_fixed_asset:(:428-429), a server-set field. - The chain reaches
depreciation.py:481and thenasset_depreciation_schedule.py:215-217, which callscurrent_schedule.cancel()on adocstatus == 1, submittableAsset Depreciation Schedulethrough the document lifecycle (onlyshould_not_cancel_depreciation_entriesis set, notignore_validate, sobefore_canceldoes fire and the ride is what admitted it).
So one marker authorising submit Sales Invoice X cancelled a submitted document the human was never shown and never approved. Cancelling such a document reverses its ledger effect.
The same shape exists behind wider grants, for example Unreconcile Payment.on_submit (unreconcile_payment.py:59-64), which walks a child table the caller fills and reaches accounts/utils.py:857/:859 gain_loss_je.cancel() on submitted Journal Entries.
Who is affected
Only sites that had opted into consent gating: a credential must hold an API Key Scope with require_consent set. pacioli-guard is inert for principals without such a grant, and the credential-scoping floor (auth_hooks) is unaffected by this issue.
The document-layer consent gate was first published in 0.9.6, which is the only released version in the affected range.
Patches
Fixed in 0.10.0. The ride now discriminates on the enclosing act: an undo may cascade into further undos, but a submit may not cascade into the cancellation of a document that already has a name, because that is an act a human could have been asked to approve. The custody stamp carries the act it was established for rather than a bare boolean, which is the state the vulnerable code lacked.
Upgrading changes behavior. Any ERPNext flow where a submit cascades into a lifecycle cancel now requires a consent marker for that cancel as well as for the act itself. In ERPNext v16 that includes asset sale, partial-quantity asset sale, a credit note against an asset sale, Asset Repair capitalization, Asset Shift Allocation, Asset Value Adjustment, and Unreconcile Payment. To make that possible, the X-Pacioli-Consent header now accepts several markers separated by whitespace or commas; each remains bound to one document and one act, requires a different minter, and is spent exactly once.
Workarounds
On 0.9.6, remove require_consent from affected grants and rely on the credential-scoping floor alone, or scope governed credentials so they cannot submit documents whose controllers cancel other documents (for ERPNext slice-one, Sales Invoice with…
- Record
PYSEC-2026-4246- CVSS 3.1
- 5.7 Medium
CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:N/I:H/A:N - Updated
- 2026-11-02
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
pacioli-guardPyPI |
0.9.6 up to 0.10.0 | 0.10.0 |
History
| Recorded | Changed | Sources |
|---|---|---|
| first indexed | CVE List, EUVD, GitHub Advisories, NVD, OSV |
Dates are when Every CVE recorded each change. Upstream dates may differ.
In short
CVE-2026-107841 is a medium vulnerability (CVSS 5.7) in John-broadway Pacioli, published October 9, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.23%, the 14th percentile. Fixed in pacioli-guard 0.10.0.
References
github.com/john-broadway/pacioli/security/advisories/GHSA-3hj7-6vmj-h8v4
github.com/john-broadway/pacioli/commit/f3c7219f5dde6050bd7921e0ac55afd02771250c
github.com/john-broadway/pacioli/releases/tag/guard-v0.10.0
nvd.nist.gov/vuln/detail/CVE-2026-107841
github.com/advisories/GHSA-3hj7-6vmj-h8v4
github.com/CVEProject/cvelistV5/tree/main/cves/2026/107xxx/CVE-2026-107841.json
github.com/john-broadway/pacioli
pypi.org/project/pacioli-guard
Left out here: the rest of 3 source descriptions. The JSON record has them.