Attack ChainAIDerived
Hypothetical attack flow derived from CVE metadata – not a confirmed exploit chain
-
AccessObtain a valid or expired EmailLog token link
-
DeliverySubmit token to /customer/invoices|estimates|payments JSON route
-
ExploitServer skips mailable_type and expiry checks
-
ExecutionColliding numeric id resolves foreign document
-
ImpactDisclose another company's invoice/estimate/payment and mark it viewed
Vulnerability Assessment
| Weakness |
CWE
OWASP Top 10:2025
A01:2025 - Broken Access Control
ASVS 5.0
V8 - Authorization Authorization verification
MITRE ATT&CK
1 technique across 1 tactic: Defense Evasion The technique list with ATT&CK links and the kill-chain view is part of the Basic plan and up. |
| Exploitation Conditions | Exploitation targets the public customer routes GET /customer/invoices/{email_log:token}, GET /customer/estimates/{email_log:token}, and GET /customer/payments/{email_log:token} on InvoiceShelf versions prior to 2.4.0. The attacker must possess a valid EmailLog token (an email link issued to any customer); no account authentication is required (PR:N). Two concrete conditions enable abuse: (1) the JSON handlers resolve $emailLog->mailable_id without verifying mailable_type, so a token issued for one document type discloses a different company's document when numeric identifiers COLLIDE across tenants - this id collision is the limiting factor and is opportunistic, not attacker-controlled; (2) the JSON handlers did not enforce EmailLog::isExpired, so an EXPIRED token remains usable - this path needs only an old link and is fully reliable. The view handlers additionally require the target invoice/estimate to be in STATUS_SENT or STATUS_DRAFT to flip it to 'viewed' and send a notification. The flaw requires no special server configuration; it affects default deployments of vulnerable versions. |
| Impact | This is a genuine authorization flaw (CWE-285), not a high-CVSS-but-low-risk artifact, but the real-world priority is moderated by product footprint and exploitation prerequisites. The CVSS 3.1 vector (AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:L/A:N, base 8.2) correctly reflects remote, unauthenticated, network-reachable access to the public customer JSON routes, with high confidentiality impact (cross-company document disclosure) and low integrity impact (a mismatched invoice/estimate can be marked 'viewed' and trigger a notification email). No availability impact. There is no EPSS score, no CISA KEV listing, and no public POC supplied in the input, so exploitation likelihood signals are absent - meaning no public exploit identified at time of analysis. One nuance to flag explicitly: the most impactful variant (disclosing a DIFFERENT company's document) requires the attacker's own valid EmailLog token's numeric mailable_id to collide with another company's document id across mailable types, which is opportunistic/targeted rather than reliably controllable - this makes AC arguably higher than AC:L for that path. The simpler, fully reliable path is reuse of an EXPIRED token on the JSON routes (the handlers did not enforce EmailLog::isExpired), which needs only possession of a now-expired link. Net: a real authorization/IDOR-class issue worth prompt patching, but absent KEV/EPSS/POC signals and given a niche self-hosted product, it is a moderate operational priority rather than an emergency. |
| Exploit ScenarioDerived | An attacker who legitimately received an InvoiceShelf email link (an EmailLog token) replays it after expiry, or substitutes it against the customer JSON routes, and retrieves invoice, estimate, or payment data. Where the token's numeric mailable_id collides with another tenant's document id, the response discloses a different company's financial document; requesting an estimate/invoice can also flip its status to 'viewed' and dispatch a notification email. No public exploit code is referenced in the input, and the network-reachable, low-complexity, unauthenticated routes make the expired-token reuse path straightforward. |
Get an e-mail when this CVE is exploited, patched or re-scored. Free account.
Alert meAnalysisAIv1 – Oct 14, 2026
InvoiceShelf installs prior to 2.4.0 leak other customers' invoices, estimates, and payment PDFs through the public customer-portal token routes, because the EmailLog token is resolved by numeric mailable_id without checking mailable_type and the JSON handlers never enforce EmailLog::isExpired. An unauthenticated remote attacker holding any legitimate emailed customer link (PR:N, no account needed) can therefore retrieve a document belonging to a different company when numeric identifiers collide across tenants, or keep using an already-expired link indefinitely on the JSON routes GET /customer/invoices/{email_log:token}, GET /customer/estimates/{email_log:token}, and GET /customer/payments/{email_log:token}; the view handlers can additionally flip a mismatched invoice or estimate to 'viewed' and trigger a notification email. Rated CVSS 8.2 (C:H, I:L) as a genuine improper-authorization flaw (CWE-285), though the cross-tenant variant is opportunistic and gated by id collisions while the expired-token variant is fully reliable; no public exploit code has been identified at time of analysis and the issue is fixed in version 2.4.0.
RemediationAI
Upgrade to InvoiceShelf 2.4.0, which is the vendor-released patch and the version that replaces the raw mailable_id lookups with the type-checked $emailLog->mailable relation and applies abort_if($emailLog->isExpired(), 403, 'Link Expired.') on every PDF, JSON, and view path; the fix is delivered via commit 5839d8385debf379644f55e773639e1c7e673163 (PR 662) and documented in GHSA-73q7-2953-8gvx. If an immediate upgrade is not possible, compensating controls should target the two abuse paths: invalidate or delete stale EmailLog rows and shorten the token validity window in configuration so expired links stop resolving, accepting that this breaks legitimate customer links already sent by email and requires re-sending them; and treat any customer-portal token as cross-tenant sensitive by rate-limiting or IP-restricting the /customer/invoices, /customer/estimates, and /customer/payments token routes at the reverse proxy, at the cost of added friction for genuine customers and possible false positives on shared NAT egress. Because the cross-tenant disclosure depends on numeric id collisions, avoid sequential per-tenant id ranges as a stopgap only if a backport is infeasible, and monitor web logs for repeated token-route requests across unrelated company ids or for tokens older than the configured expiry, since such patterns indicate active probing. Note that no vendor-released patch exists for versions below 2.4.0 other than the upstream commit itself, so the 2.4.0 upgrade is the authoritative remediation.
Affected VersionsENISA
Affected Packages
Source: OSV (Open Source Vulnerabilities)
Affects your stack
Affects 1 package in euvd
Checking this CVE against your own stacks and servers is part of the Basic plan and up.
Technical ContextAI · show details
InvoiceShelf is a Laravel (PHP) invoicing application whose EmailLog model stores outbound email links using a polymorphic pair: a numeric mailable_id plus a mailable_type discriminator. The vulnerable controllers (EstimatePdfController, InvoicePdfController, PaymentPdfController) performed Estimate::find($emailLog->mailable_id), Invoice::find($emailLog->mailable_id), and Payment::find($emailLog->mailable_id) directly, discarding the mailable_type, so the type check that polymorphic relations normally provide was bypassed; this is a classic CWE-285 improper authorization defect in which the object reference is not validated against the principal's entitlement. Two distinct weaknesses follow: documents are looked up in the wrong table whenever a token issued for one mailable type is paired with a colliding numeric id in another company's records, and the expiry guard (EmailLog::isExpired) was applied only on some paths, leaving the JSON handlers able to serve expired links. The upstream fix replaces the raw find() with the $emailLog->mailable relation plus abort_unless($doc instanceof Invoice|Estimate|Payment, 404) and abort_if($emailLog->isExpired(), 403, 'Link Expired.'), which both restores type enforcement and makes expiry checks uniform across PDF/JSON/view handlers. Attack surface is network-reachable with no authentication or user interaction (AV:N/AC:L/PR:N/UI:N), and the confidentiality impact is high because full invoice, estimate, or payment documents-billing details, customer data, amounts-are returned; integrity impact is limited to status transitions (SENT/DRAFT to VIEWED) and the resulting notification email, hence I:L.
Know when the next one hits your stack
- Watch products and get an email when something new is published
- Check this CVE against your own stack and servers
- Exploit and PoC references, threat intelligence from 22 sources
No credit card · 7-day full trial
Severity by source
AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:L/A:N
Public token routes are unauthenticated and network-reachable (AV:N/PR:N/UI:N); the reliable expired-token reuse path keeps AC:L; cross-company disclosure gives C:H and status/notification writes give I:L, no availability impact.
Primary rating from Vendor (github).
CVSS VectorVendor: github
Lifecycle Timeline
2DescriptionCVE.org
InvoiceShelf is an open-source web & mobile app that helps track expenses, payments and create professional invoices and estimates. Prior to version 2.4.0, InvoiceShelf public customer invoice, estimate, and payment routes use an EmailLog token's numeric mailable_id without verifying mailable_type, and the JSON handlers do not enforce EmailLog::isExpired. A token issued for one document type can therefore disclose a different company's document when numeric identifiers collide, and an expired token can remain usable on the JSON routes GET /customer/invoices/{email_log:token}, GET /customer/estimates/{email_log:token}, and GET /customer/payments/{email_log:token}. View handlers can also mark a mismatched invoice or estimate as viewed and send a notification. This issue is fixed in version 2.4.0.
Technical POC Analysis
Improper authorization (CWE-285) implemented as a type-confusion on Laravel route-model-bound tokens.
Full technical POC analysis - root cause, step-by-step exploitation and patch breakdown - is part of the Pro and Business plans.
Executive ViewAI
InvoiceShelf deployments prior to 2.4.0 can expose customer invoices, estimates, and payment PDFs across customer accounts because the customer-portal token routes may resolve emailed links to the wrong tenant or continue accepting expired links. The issue is unauthenticated and rated CVSS 8.2, so any organization hosting an affected instance faces potential confidentiality loss and cross-tenant trust erosion, with no public exploit identified at time of analysis. Leadership should treat this as a customer-data protection and compliance risk, especially where InvoiceShelf is internet-facing or used by multiple client organizations.
No vendor-released patch identified at time of analysis; interim mitigations include restricting or disabling the public token routes GET /customer/invoices/{email_log:token}, GET /customer/estimates/{email_log:token}, and GET /customer/payments/{email_log:token} where possible, invalidating and reissuing emailed customer links, monitoring those endpoints for anomalous or cross-tenant access, limiting InvoiceShelf exposure to trusted networks, and applying virtual patching/WAF rules while awaiting a vendor fix.
Threat Intelligence Overview
How this decision was reached
The engine reads each signal below and applies a fixed list of rules from top to bottom. The first rule that matches sets the recommended action – like a statement, every line is shown.
What every action level means
SSVC AssessmentENISA
Priority Score
Attack Technique
Authentication bypass attacks exploit flaws in the verification mechanisms that control access to systems and applications.
EUVD-2026-101610
NVD
CVE.org
EPSS
Vulnrichment
GitHub
Exploit-DB