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`) calls `process_asset_depreciation()` unconditionally, reaching `depreciate_asset_on_sale` (`:1508-1516`). - That iterates the invoice's item rows and calls `frappe.get_doc("Asset", d.asset)`. `Sales Invoice Item.asset` is a plain writable `Link` with no `read_only` and no `fetch_from`, so the caller supplies it in the request body. The validation that would constrain it sits behind `if d.is_fixed_asset:` (`:428-429`), a server-set field. - The chain reach
- Products
- pacioli-guard
- Affected versions
- 0.9.6
- Fixed versions
- 0.10.0
- CVEs
- CVE-2026-107841
- Confirmed fixed CVEs
- Not specified
- Updated in this feed
- 30 Oct 2026, 18:15 UTC · Revision 1
Source evidence
pacioli: A submit consent marker licensed cancellation of caller-named pre-existing documents
core-osv · Original sourcePublished 9 Oct 2026, 20:42 UTC
### 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`) calls `process_asset_depreciation()` unconditionally, reaching `depreciate_asset_on_sale` (`:1508-1516`). - That iterates the invoice's item rows and calls `frappe.get_doc("Asset", d.asset)`. `Sales Invoice Item.asset` is a plain writable `Link` with no `read_only` and no `fetch_from`, so the caller supplies it in the request body. The validation that would constrain it sits behind `if d.is_fixed_asset:` (`:428-429`), a server-set field. - The chain reach
osv:GHSA-3hj7-6vmj-h8v4
pacioli-guard
Fixed versions: 0.10.0
Complete source record
{
"id": "3d89e44e59803b2b155b2bd563c5d4e746c0a78c148832eaae3bafca5b4d98a7",
"url": "https://osv.dev/vulnerability/GHSA-3hj7-6vmj-h8v4",
"method": "structured",
"payload": {
"kind": "advisory",
"title": "pacioli: A submit consent marker licensed cancellation of caller-named pre-existing documents",
"summary": "### 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`) calls `process_asset_depreciation()` unconditionally, reaching `depreciate_asset_on_sale` (`:1508-1516`). - That iterates the invoice's item rows and calls `frappe.get_doc(\"Asset\", d.asset)`. `Sales Invoice Item.asset` is a plain writable `Link` with no `read_only` and no `fetch_from`, so the caller supplies it in the request body. The validation that would constrain it sits behind `if d.is_fixed_asset:` (`:428-429`), a server-set field. - The chain reach",
"evidence": "osv:GHSA-3hj7-6vmj-h8v4",
"products": [
{
"name": {
"value": "pacioli-guard",
"evidence": "/affected/0/package/name"
},
"prerequisites": [],
"fixed_versions": [
{
"value": "0.10.0",
"evidence": "/affected/0/ranges"
}
],
"affected_versions": [
{
"value": "0.9.6",
"evidence": "/affected/0/versions"
}
]
}
],
"severity": "medium",
"structured": {
"id": "GHSA-3hj7-6vmj-h8v4",
"aliases": [
"CVE-2026-107841",
"GHSA-3hj7-6vmj-h8v4",
"PYSEC-2026-4246"
],
"metrics": [
{
"type": "CVSS_V3",
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:N/I:H/A:N"
}
],
"affected": [
{
"ranges": [
{
"type": "ECOSYSTEM",
"events": [
{
"introduced": "0.9.6"
},
{
"fixed": "0.10.0"
}
]
}
],
"package": {
"name": "pacioli-guard",
"purl": "pkg:pypi/pacioli-guard",
"ecosystem": "PyPI"
},
"versions": [
"0.9.6"
],
"database_specific": {
"source": "https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/10/GHSA-3hj7-6vmj-h8v4/GHSA-3hj7-6vmj-h8v4.json"
}
}
],
"modified": "2026-10-15T14:55:55.450927331Z",
"provider": "osv",
"references": [
"https://github.com/john-broadway/pacioli/security/advisories/GHSA-3hj7-6vmj-h8v4",
"https://nvd.nist.gov/vuln/detail/CVE-2026-107841",
"https://github.com/john-broadway/pacioli/commit/f3c7219f5dde6050bd7921e0ac55afd02771250c",
"https://github.com/john-broadway/pacioli",
"https://github.com/john-broadway/pacioli/releases/tag/guard-v0.10.0"
],
"provider_metadata": {
"cwe_ids": [
"CWE-863"
],
"severity": "MODERATE",
"github_reviewed": true,
"nvd_published_at": "2026-10-09T18:17:06Z",
"github_reviewed_at": "2026-10-09T20:42:51Z"
}
},
"related_cves": [
{
"value": "CVE-2026-107841",
"evidence": "/aliases"
}
],
"security_relevant": true,
"severity_evidence": "/severity/0/score"
},
"source_id": "core-osv",
"document_id": 332684,
"published_at": "2026-10-09T20:42:51+00:00"
}pacioli: A submit consent marker licensed cancellation of caller-named pre-existing documents
core-osv · Original sourcePublished 15 Oct 2026, 10:22 UTC
### 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`) calls `process_asset_depreciation()` unconditionally, reaching `depreciate_asset_on_sale` (`:1508-1516`). - That iterates the invoice's item rows and calls `frappe.get_doc("Asset", d.asset)`. `Sales Invoice Item.asset` is a plain writable `Link` with no `read_only` and no `fetch_from`, so the caller supplies it in the request body. The validation that would constrain it sits behind `if d.is_fixed_asset:` (`:428-429`), a server-set field. - The chain reach
osv:PYSEC-2026-4246
pacioli-guard
Fixed versions: 0.10.0
Complete source record
{
"id": "e4af5611fc21925e9ffe99bda3742c470765743b90644433c7f50445aa7af2f3",
"url": "https://osv.dev/vulnerability/PYSEC-2026-4246",
"method": "structured",
"payload": {
"kind": "advisory",
"title": "pacioli: A submit consent marker licensed cancellation of caller-named pre-existing documents",
"summary": "### 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`) calls `process_asset_depreciation()` unconditionally, reaching `depreciate_asset_on_sale` (`:1508-1516`). - That iterates the invoice's item rows and calls `frappe.get_doc(\"Asset\", d.asset)`. `Sales Invoice Item.asset` is a plain writable `Link` with no `read_only` and no `fetch_from`, so the caller supplies it in the request body. The validation that would constrain it sits behind `if d.is_fixed_asset:` (`:428-429`), a server-set field. - The chain reach",
"evidence": "osv:PYSEC-2026-4246",
"products": [
{
"name": {
"value": "pacioli-guard",
"evidence": "/affected/0/package/name"
},
"prerequisites": [],
"fixed_versions": [
{
"value": "0.10.0",
"evidence": "/affected/0/ranges"
}
],
"affected_versions": [
{
"value": "0.9.6",
"evidence": "/affected/0/versions"
}
]
}
],
"severity": "medium",
"structured": {
"id": "PYSEC-2026-4246",
"aliases": [
"CVE-2026-107841",
"GHSA-3hj7-6vmj-h8v4",
"PYSEC-2026-4246"
],
"metrics": [
{
"type": "CVSS_V3",
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:N/I:H/A:N"
}
],
"affected": [
{
"ranges": [
{
"type": "ECOSYSTEM",
"events": [
{
"introduced": "0.9.6"
},
{
"fixed": "0.10.0"
}
]
}
],
"package": {
"name": "pacioli-guard",
"purl": "pkg:pypi/pacioli-guard",
"ecosystem": "PyPI"
},
"versions": [
"0.9.6"
],
"database_specific": {
"source": "https://github.com/pypa/advisory-database/blob/main/vulns/pacioli-guard/PYSEC-2026-4246.yaml"
}
}
],
"modified": "2026-10-15T14:45:12.948309515Z",
"provider": "osv",
"references": [
"https://github.com/john-broadway/pacioli/security/advisories/GHSA-3hj7-6vmj-h8v4",
"https://nvd.nist.gov/vuln/detail/CVE-2026-107841",
"https://github.com/john-broadway/pacioli/commit/f3c7219f5dde6050bd7921e0ac55afd02771250c",
"https://github.com/john-broadway/pacioli",
"https://github.com/john-broadway/pacioli/releases/tag/guard-v0.10.0",
"https://pypi.org/project/pacioli-guard",
"https://github.com/advisories/GHSA-3hj7-6vmj-h8v4"
]
},
"related_cves": [
{
"value": "CVE-2026-107841",
"evidence": "/aliases"
}
],
"security_relevant": true,
"severity_evidence": "/severity/0/score"
},
"source_id": "core-osv",
"document_id": 332656,
"published_at": "2026-10-15T10:22:55.058463+00:00"
}