~/en/research $ cat case-003.md

PaperCut NG/MF: from an authentication bypass to loading any class you name

CVSS 9.4 · critical CVE-2026-82078 CVE-2026-81578 PaperCut NG/MF CWE-470

Reconstruction of the chain PaperCut disclosed on 27 August 2026: improper access to the administration interface allows rewriting the database configuration, and the dynamic class loading in the connector then runs the class that configuration names. The case measures when it fires and when it dies on each vendor version.

What was published and how it was recorded

On 27 August 2026 PaperCut issued an urgent bulletin with two CVEs published in NVD on 28 August: CVE-2026-81578, improper access control in the administration web interface, and CVE-2026-82078, insecure dynamic class loading in the database connector. The ratings are recorded literally and without blending: the CNA gives CVSS 4.0 8.8 (High) to the first and 9.4 (Critical) to the second, and NVD gives CVSS 3.1 9.8 and 9.1. The CWE also contradicts itself inside the vendor material (CWE-305 versus CWE-306) and is noted exactly as written, with no invented winner.

The maintenance fixes are 24.1.10, 25.0.13 and 26.0.5, published on 10 September 2026 to replace the emergency patches EPR1 through EPR3. Because the fix commit is not public (closed source), the case works through behavioral A/B and without decompilers.

Both CVEs entered the CISA KEV catalog on 2026-08-31 with a due date of 2026-09-14.

The chain in three moves

CVE-2026-81578 lets an unauthenticated remote request reach a Tapestry "complex direct" service route before access validation finishes: a forged POST rewrites system configuration. CVE-2026-82078 makes the database connector instantiate whatever the user-lookup.db-driver parameter names, via Class.forName before connecting, with no allowlist.

The chained result: pointing that parameter at a class already resident in the application classpath runs its static initializer as the PaperCut service user. A single HTTP session with no credentials is enough: no file upload, no account theft. The class used as proof of execution is 977 bytes already present in the product.

The parent process behind the kill-shot is measured, not asserted: the shell's sh reports the pc-app JVM process as its parent.

What the agent did and what it measured

The lab is three branches (stock 25.0.11, EPR3 25.0.12-PO-4560.76533 and 25.0.13) on a Docker --internal network with no internet egress, with factory restoration between runs and proven by cold reads of the database.

The closure matrix ran on the same day with the same exploit bytes: it fires on 25.0.11 and goes quiet at step 3 of 11 on both fixed branches, with the five-pillar gate VALID 5/5. And inside the fixed build, the same PoC class bytes still execute if they are forced to load: the fix closes the authorization path, not the executable artifact.

The fix was located without decompilers, comparing the papercut.application service override of the stock branch with the two patched ones (byte-identical to each other) and the hashes of the Tapestry engine jars (identical across the three branches). The package self-audits with a claim gate: claims=32 checks=32 pass=32 fail=0, with the 12 pages of the paper audited one by one.

Where the agent stopped

This case publishes its failures in a 49-entry attempt log. The intake checksum gate returned MISMATCH against the wrong row of the vendor bulletin (#1), a confabulated sink location was caught by the self-audit before anyone consumed it (#2), a destructive rebuild killed a green container mid-run (#5) and the database reads taken with the database open were invalidated (#8).

The most instructive entry is #12: in two of three kill-shot runs the chain worked all three times, but the capture was defective on the harness side and had to be obtained again. The video production cycle, including the re-shoot, is published in entries #18 to #43.

Detection also saw honest trims: a network rule that also fired on the patched branches was renamed to attempt level, and the YARA rules that look for lab traces are labeled LAB-TRACE and excluded from the findings set. Not established: the prevalence of real-world exploitation, a complete audit of the closed-source code, and whether any intermediate emergency patch revision remains bypassable.

Detection and remediation

The recommended first step is passive and does not touch the service: check the version band (all PaperCut NG and MF 24.1 before 24.1.10, 25.0 before 25.0.13 and 26.0 before 26.0.5) and run the read-only audit detect_papercut_82078.py --audit. Updating to 24.1.10, 25.0.13 or 26.0.5 closes the chain; the intermediate EPRs are not the end state.

The detection package ships with Suricata (7 CVE rules plus one sensor-health rule, so that a zero is not vacuous), Sigma for process lineage and log shape with its fire or trim record, YARA for artifact remnants, and a vendor IoC mapping cross-checked against the lab shape. The rules are replayed against the published pcaps with run_suricata.sh, never against a live interface.

The signatures that count are shape signatures, not lab filenames: the DatabaseUtils line carrying an attacker card value to the sink, Derby booting the memory DB, the configuration table churn and the PaperCut JVM spawning an interactive shell.

Results

  • Full chain on stock 25.0.11.75758: an unauthenticated forged request rewrites the database driver configuration, loads a 977-byte proof-of-execution class already resident in the classpath and runs as uid=1000(papercut), with factory restoration proven by cold reads of the database.
  • Measured closure matrix: 25.0.11 fires; EPR3 25.0.12-PO-4560.76533 dies at step 3 of 11 (302 bounce from the forged request); 25.0.13 dies at the same step. Runs on the same day, exploit bytes intact and the five-pillar gate VALID 5/5.
  • The fix was located without decompilers: diff of the papercut.application service override between the stock branch and the two patched ones (byte-identical to each other) and identical hashes for the Tapestry engine jars across the three branches.
  • Corroboration inside the fixed build: the same PoC class bytes still execute if they are forced to load on the EPR3 branch, so the fix closes the authorization path, not the executable artifact.
  • Case claim gate: claims=32 checks=32 pass=32 fail=0, with the 12 pages of the paper audited page by page.
~/contactreply < 24 business hours · es / en

you@nullsector:~$ mail miguel

[email protected]

Collaborations, talks, press or research: write to me.

Need a pentest or a vulnerability assessment? Request it at Xpectra.ai ↗