Skip to main content
CVE Vulnerability Database
Vulnerability Database/CVE-2026-71242

CVE-2026-71242: Crater Auth Bypass Vulnerability

CVE-2026-71242 is an authentication bypass flaw in Crater that allows authenticated users to read, edit, or delete notes belonging to other companies. This article covers technical details, affected versions, and mitigation.

Published:

CVE-2026-71242 Overview

CVE-2026-71242 is a broken access control flaw in Crater, an open-source invoice management application. The NotePolicy class enforces only a blanket Bouncer ability (manage-all-notes / view-all-notes) and omits the company-ownership check that sibling policies such as InvoicePolicy perform via $user->hasCompany($model->company_id). Any authenticated user in one company tenant can read, edit, or delete notes belonging to another company by supplying a target note ID. The flaw is classified under CWE-639: Authorization Bypass Through User-Controlled Key.

Critical Impact

Authenticated users of any tenant can view, modify, or destroy other tenants' notes by referencing the target note ID, breaking multi-tenant isolation in Crater.

Affected Products

  • Crater (self-hosted invoicing application)
  • NotePolicy authorization class
  • NotesControllershow(), update(), and destroy() actions

Discovery Timeline

  • 2026-08-05 - CVE-2026-71242 published to NVD
  • 2026-08-05 - Last updated in NVD database

Technical Details for CVE-2026-71242

Vulnerability Analysis

Crater implements multi-tenant separation by associating each record with a company_id and by scoping policies to that identifier. InvoicePolicy and comparable sibling policies check both a Bouncer ability and $user->hasCompany($model->company_id) before granting access. NotePolicy diverges from this pattern. It only validates the Bouncer abilities manage-all-notes and view-all-notes and never compares the note's owning company to the caller's company. Authenticated users in any tenant typically hold these abilities by default, so the policy effectively authorizes cross-tenant access.

The controller compounds the flaw. NotesController::show(), update(), and destroy() call $this->authorize('view notes') or $this->authorize('manage notes') without passing the specific Note model instance. Laravel's authorization layer therefore evaluates the class-level policy rather than a model-bound check. The Note model's scopeWhereCompany query scope is applied only in the list endpoint, so single-record retrieval and mutation bypass tenant scoping entirely.

Root Cause

The root cause is a missing ownership predicate inside NotePolicy. The policy grants access on ability alone and does not confirm that the acting user belongs to the same company as the target Note. Combined with the controller passing no model to authorize() and the missing whereCompany scope on single-record queries, the object reference (note_id) becomes the sole access control gate.

Attack Vector

An authenticated user in tenant A enumerates or guesses a numeric note_id belonging to tenant B and issues GET, PUT, or DELETE requests against the notes endpoint. The NotePolicy returns true based on the caller's blanket ability, the controller loads the note without a company filter, and the operation succeeds against tenant B's data. Exploitation requires only valid session credentials and knowledge or enumeration of a target note ID.

No verified public proof-of-concept code is available. See the Crater repository for policy and controller source.

Detection Methods for CVE-2026-71242

Indicators of Compromise

  • Application log entries showing GET, PUT, or DELETE requests to /api/v1/notes/{id} where the responding note's company_id does not match the authenticated user's company.
  • Sudden appearance of modified or missing notes reported by tenants who did not initiate the change.
  • Sequential or fuzzed note_id enumeration patterns from a single authenticated session.

Detection Strategies

  • Instrument NotesController to log the caller's company_id alongside the target note's company_id and alert on mismatches.
  • Correlate authentication session identifiers with accessed note_id values in web server logs to surface cross-tenant access patterns.
  • Run periodic database audits comparing note modification timestamps against user session tenants recorded in application logs.

Monitoring Recommendations

  • Forward Crater application and web server logs to a centralized SIEM and build rules for cross-tenant object access anomalies.
  • Track 4xx and 5xx spikes on /notes/{id} endpoints that may indicate ID enumeration attempts.
  • Alert on any account that accesses notes at a volume or pattern inconsistent with its historical tenant activity.

How to Mitigate CVE-2026-71242

Immediate Actions Required

  • Update NotePolicy to include $user->hasCompany($model->company_id) in every ability method, matching InvoicePolicy.
  • Modify NotesController::show(), update(), and destroy() to pass the resolved Note instance to $this->authorize() so the policy receives the model.
  • Apply the scopeWhereCompany query scope to single-record lookups, not just list queries.
  • Audit application logs for prior cross-tenant note access and notify affected tenants.

Patch Information

Monitor the Crater GitHub repository for the upstream fix. Until an official release includes the ownership check, self-hosted operators should apply a local patch that adds the company comparison to NotePolicy and binds the Note model in controller authorize() calls.

Workarounds

  • Restrict network access to the Crater instance to trusted users while the patch is developed.
  • Revoke the view-all-notes and manage-all-notes Bouncer abilities from standard tenant roles if operations allow.
  • Add a middleware layer that rejects any /notes/{id} request whose loaded note's company_id does not match the session's company_id.
bash
# Example middleware guard (pseudocode) enforcing tenant match on note routes
# Place before NotesController show/update/destroy in routes/api.php
Route::middleware(['auth:sanctum', 'tenant.note.owner'])
    ->group(function () {
        Route::get('/notes/{note}', [NotesController::class, 'show']);
        Route::put('/notes/{note}', [NotesController::class, 'update']);
        Route::delete('/notes/{note}', [NotesController::class, 'destroy']);
    });

Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

Default Legacy - Prefooter | Experience the World’s Most Advanced Cybersecurity Platform

Experience the Most Advanced Cybersecurity Platform

See how the world’s most intelligent, autonomous cybersecurity platform can protect your organization today and into the future.