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

CVE-2026-59708: Ghostfolio Auth Bypass Vulnerability

CVE-2026-59708 is an authentication bypass vulnerability in Ghostfolio that allows unauthenticated access to sensitive portfolio data via private access IDs. This article covers technical details, affected versions, and mitigation.

Published:

CVE-2026-59708 Overview

CVE-2026-59708 is a missing authorization vulnerability [CWE-862] in Ghostfolio, an open-source wealth management application. The GET /api/v1/public/:accessId/portfolio endpoint accepts private access identifiers without validating the granteeUserId filter. An unauthenticated attacker who obtains a private access ID can retrieve full portfolio data through the public route. Exposed data includes holdings, quantities, buy prices, and performance metrics. The vulnerability affects confidentiality of financial records but does not permit modification.

Critical Impact

Unauthenticated attackers holding a private access ID can exfiltrate complete portfolio contents, including positions, cost basis, and performance figures, from any affected Ghostfolio instance.

Affected Products

  • Ghostfolio wealth management platform
  • Self-hosted Ghostfolio deployments exposing the /api/v1/public route
  • Ghostfolio SaaS instances prior to the fix in commit 697ef59

Discovery Timeline

  • 2026-07-07 - CVE-2026-59708 published to NVD
  • 2026-07-09 - Last updated in NVD database

Technical Details for CVE-2026-59708

Vulnerability Analysis

Ghostfolio distinguishes between public access tokens, which are intended to expose a sanitized read-only view, and private access tokens, which are meant for authenticated sharing scoped to a specific grantee user. The public portfolio endpoint fails to enforce this distinction. When the endpoint receives an accessId value, it retrieves the associated access record and returns portfolio data without verifying that the record is of the public type or that granteeUserId matches the caller. The result is a broken access control condition classified under CWE-862 Missing Authorization. Any party in possession of a private access ID, including IDs leaked through logs, referrers, browser history, or backups, can query the public endpoint anonymously and receive holdings, transaction quantities, buy prices, and derived performance metrics.

Root Cause

The handler for /api/v1/public/:accessId/portfolio retrieves the access record by ID alone. It omits the predicate that restricts results to entries where the access type is public and where granteeUserId is null or matches the requester. The authorization boundary is therefore enforced by URL path rather than by data model constraints.

Attack Vector

Exploitation is network-based and requires no authentication, no user interaction, and no elevated privileges. An attacker submits an HTTP GET request to the public endpoint using a known or guessed private accessId. The server responds with the full portfolio JSON payload belonging to the owner of that access record.

The upstream fix is delivered in commit 697ef59e3b58bebc5c21a9e482e4f5643390f316 in the ghostfolio repository. The patch adjusts service wiring in the fetch module, including the addition of PropertyModule to apps/api/src/services/fetch/fetch.module.ts, alongside the authorization checks required to reject private access IDs on the public route. Refer to the Vulncheck security advisory and GitHub issue #7197 for the full technical write-up.

Detection Methods for CVE-2026-59708

Indicators of Compromise

  • Unauthenticated GET requests to /api/v1/public/:accessId/portfolio from unfamiliar IP ranges or automated clients.
  • Access log entries where the same client enumerates multiple distinct accessId values in a short interval.
  • Requests using accessId values that correspond to access records with a non-public type in the database.
  • Elevated response sizes on the public portfolio endpoint indicating full data payloads rather than sanitized subsets.

Detection Strategies

  • Correlate application logs with the Ghostfolio access table to flag any hit on /api/v1/public/* where the referenced record is private.
  • Deploy a reverse-proxy rule that logs and rate-limits high-frequency access to /api/v1/public/:accessId/portfolio.
  • Alert on requests to the public route lacking a Referer header from the Ghostfolio front end when combined with sequential ID probing.

Monitoring Recommendations

  • Ship NGINX or reverse-proxy logs to a centralized SIEM and build a query for anonymous access to public portfolio routes over time.
  • Track database read patterns on the access and portfolio tables for spikes originating from the public API service account.
  • Monitor egress volume from the Ghostfolio API container for anomalous JSON response sizes indicative of bulk portfolio exfiltration.

How to Mitigate CVE-2026-59708

Immediate Actions Required

  • Update Ghostfolio to a release containing commit 697ef59e3b58bebc5c21a9e482e4f5643390f316 or later.
  • Rotate every private access ID currently issued, as any that were shared or logged should be considered exposed.
  • Restrict the /api/v1/public route at the reverse proxy to trusted networks until patching is complete.
  • Audit access logs for the affected endpoint across the exposure window and notify users whose portfolios were queried.

Patch Information

The upstream fix is committed to the Ghostfolio repository under commit hash 697ef59e3b58bebc5c21a9e482e4f5643390f316. Self-hosted operators should pull the latest tagged release, rebuild the API container, and redeploy. SaaS users are covered once the maintainers roll the fix to production. Review the commit details before applying.

typescript
// Excerpt from apps/api/src/services/fetch/fetch.module.ts (patch)
 import { FetchService } from '@ghostfolio/api/services/fetch/fetch.service';
+import { PropertyModule } from '@ghostfolio/api/services/property/property.module';

 import { Module } from '@nestjs/common';

 @Module({
   exports: [FetchService],
+  imports: [PropertyModule],
   providers: [FetchService]
 })
 export class FetchModule {}
// Source: https://github.com/ghostfolio/ghostfolio/commit/697ef59e3b58bebc5c21a9e482e4f5643390f316

Workarounds

  • Block or filter /api/v1/public/:accessId/portfolio at a reverse proxy for any accessId not present in an allowlist of confirmed public tokens.
  • Revoke and reissue all private access IDs, then instruct users to share portfolios only through authenticated flows.
  • Place the Ghostfolio instance behind a VPN or IP allowlist until the patched release is deployed.
bash
# NGINX example: deny the public portfolio endpoint until the patch is applied
location ~ ^/api/v1/public/[^/]+/portfolio$ {
    allow 10.0.0.0/8;
    deny all;
    return 403;
}

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.