The first PaperCut run produced the result everyone wants to see in a remote-code-execution investigation: a command marker. It still did not prove remote code execution.
The marker appeared only after the laboratory operator changed the target locally and restarted the service. An unauthenticated attacker had not performed either operation. Accepting the marker would have rewarded the visible result while erasing the missing causal edge.
A separate Pruva verification agent, which did not produce the exploit, evaluated the claim against the current-run evidence and rejected that interpretation. The run had found meaningful unauthenticated behavior, but not the claimed stock remote command execution. That rejection set the standard for the next experiment: every exploit-state change had to cross the application boundary, the effect had to be observable remotely, the proof had to repeat after resetting the target to its pre-attack state, and the unchanged sequence had to produce no command execution against the emergency-patched build.
The second run met those conditions. Prior evidence narrowed the next search without becoming an answer key. Its repeatable request sequence later became an input for defense testing and unchanged patch replay.
Cold-start control. The accepted platform run included one authenticated configuration-editor visit during ordinary setup. To test whether that visit initialized required state, we repeated the experiment in fresh containers with only the normal setup wizard and no editor page load. The RCE and the Release 1 residual still reproduced. The authenticated visit was not an exploit precondition.
Open the public proof
REPRO-2026-00340 is the publication-grade record behind this article. It packages the deterministic reproduction script, runtime manifest, accepted verdict, root-cause analysis, remote request and response evidence, and the fixed-build control. The public record also preserves the accepted Release 1 variant analysis, the full agent session, and all 451 priced model requests that produced the USD 27.174203 final workflow cost.
The published record makes the evidence independently inspectable:
bundle/repro/reproduction_steps.shrebuilds the vulnerable and controlled targets and runs the same remote sequence used by the accepted investigation;bundle/repro/validation_verdict.jsonrecordsclaim_outcome=confirmed,observed_impact_class=code_execution,evidence_scope=production_path, andend_to_end_target_reached=true;bundle/repro/runtime_manifest.jsonpins the tested runtime and build identities;bundle/repro/rca_report.mdconnects the runtime effects to the two defect classes; and- the public session and selected request, response, version, and proof artifacts show how the result evolved and why the fixed control was accepted.
Pruva produced that record as an evidence pipeline rather than a single model answer. A support stage established the stock product builds and reachable surface. A claim compiler turned the open research question into explicit attacker, entrypoint, impact, repeatability, and negative-control requirements. The reproduction agent then worked inside the real PaperCut runtime, retained failed hypotheses, and froze the successful path as a script. An independent judge accepted the RCE only after two clean vulnerable replays returned service-account command output over HTTP and the unchanged Release 1 replay returned no command receipt. The variant stage reused the proven runtime and found the residual access-control failure without weakening the original RCE verdict.
That sequence is why the public page includes more than a proof-of-concept. It exposes the causal claim, executable replay, controls, receipts, investigation trajectory, cost attribution, and variant boundary as one inspectable record. The later Release 2 test changed only the target build and replayed the frozen input, which made the patch result comparable without rediscovering the chain.
The Pruva-proven chain: CVE-2026-81578 to CVE-2026-82078
PaperCut now identifies two vulnerabilities in the attack chain. CVE-2026-81578 is an improper access-control failure that lets unauthenticated requests trigger privileged backend actions and change system configuration. CVE-2026-82078 is unsafe dynamic class loading in database utilities: attacker-influenced configuration can select code that runs under the PaperCut server process. PaperCut scores them 8.8 and 9.4 respectively.
Huntress later described the same high-level composition: one page can be trusted for rendering while a different page owns the action, allowing unauthenticated configuration changes that feed an unsafe execution path. Rapid7 also published a technical reconstruction and confirmed that the first emergency patch could be bypassed while Release 2 closes that bypass. These later public descriptions align with the vulnerability classes in Pruva’s accepted evidence; Pruva does not claim to have assigned or originally discovered either CVE.
In the reproduced chain, CVE-2026-81578 crossed the authorization boundary and changed privileged application state; CVE-2026-82078 consumed the resulting attacker-influenced configuration and reached execution under the PaperCut service identity. The variant stage then showed that Emergency Patch Release 1 had stopped the second edge without fully closing the first. The same frozen variant replay no longer reproduced that residual on Release 2 across eight attempts.
- 01Unauthenticated requestReaches the public application boundary
- 02CVE-2026-81578Privileged state changes before access validation completes
- 03Attacker-influenced configurationStock application state becomes the bridge
- 04CVE-2026-82078Unsafe class selection consumes that state
- 05Service-context executionCode runs under the PaperCut process identity
What is new in this evidence
PaperCut disclosed the incident, the affected product families, emergency updates, and several investigation indicators. Pruva’s work began from that public record.
Pruva’s accepted reproduction stage was frozen at 07:44 UTC on 28 August, before the later public technical breakdowns. Chronology is not a claim of vulnerability discovery. It establishes what our result contained at that point: a causal runtime proof rather than a conclusion copied from a subsequent write-up.
Pruva adds five runtime results:
- A command marker from the first run was rejected because the remote attacker did not own every causal step.
- A later run demonstrated unauthenticated command execution under the PaperCut service identity using application requests alone.
- The proof succeeded twice after resetting the target, while the unchanged sequence produced no command execution on the tested emergency-patched build and a benign control remained functional.
- A separate preserved-corpus harness validated two retrospective application-log hunts against attack, patched-block, and benign-control samples.
- Unchanged cold and Release 2 replays removed a suspected setup precondition and showed that the Release 1 residual no longer reproduces on build 76510.
From incident clues to a valid proof
In its 27 August urgent advisory, PaperCut reported active exploitation and confirmed customer incidents affecting PaperCut NG and MF. The company advised operators to restrict Application Server access to trusted addresses and published emergency patches for current release lines.
The bulletin also gave defenders several concrete investigation clues:
- suspicious post-exploitation activity from the PaperCut Application Server process;
- missing, truncated, or deleted
server.logfiles; - a failed JDBC-driver lookup using
jdbc:no:xat the database-driver layer; and - Card/ID lookup errors containing
VALUES CAST.
PaperCut warned that absence of those indicators does not establish that a host is clean. Its patch
FAQ also disclosed that patched builds restrict external Card/ID lookup SQL containing EXEC,
EXECUTE, or CALL. PaperCut’s Card/ID feature maps physical card identifiers to user records;
administrators can configure its external lookup behavior.
Those facts established urgency, a product surface, and useful runtime observations. They did not provide a complete causal chain that could simply be copied into a test.
The first hypothesis was useful and too certain
The initial test plan preserved the literal log signatures, identified the pre-authentication Card/ID flow as a surface worth exercising, located official installers, selected adjacent vulnerable and controlled builds, and called for inspection of the Java artifacts shipped with the product.
That preparation removed basic setup discovery from the first experiment.
The plan promoted an inferred mechanism into the claim too early. Sparse incident clues became a detailed theory of how the application might reach code execution. The mechanism was still uncertain, but the detail made the path look settled.
That distinction matters for autonomous security research. A detailed hypothesis gives the agent useful search direction, but it also makes any nearby marker look like confirmation. The first run was the experiment that separated those two things.
A real marker on the wrong side of the boundary
The initial run crossed an unauthenticated application boundary and demonstrated security-relevant control inside PaperCut. It also reached a command marker.
The marker itself was real. The causal claim was not.
The shortest route from application control to command execution required the laboratory operator to enable a non-default capability from inside the target and restart PaperCut. Those were operator actions, not remote attacker actions. A file containing command output could not repair that threat-model gap.
This is reward hacking in reproduction work: optimizing for an easy terminal signal while bypassing the causal conditions of the security claim. The marker was easy to score; the security claim still depended on ownership, reachability, and preconditions. The same separate verification agent scored the chain.
The second experiment made success harder to fake
The next experiment reused the known-good laboratory baseline, the reachable public surface, and the paths already disproven by runtime evidence. It did not receive a working exploit. Instead, it added strict proof conditions:
- ordinary product setup and every non-attacker precondition had to be recorded;
- every exploit-state mutation had to originate from unauthenticated application requests;
- local file copies, service commands, feature toggles, and target restarts were forbidden during the attacker sequence;
- command output had to return through the application boundary under the PaperCut service identity;
- the full proof had to succeed twice after resetting the target to its pre-attack state; and
- the exact same request sequence had to produce no command artifact on the emergency-patched build while a benign control still exercised the relevant feature.
Dead ends were preserved as evidence. That kept the second experiment from repeating branches whose runtime receipts were already available.
Good pre-research removes repeated setup work and known-invalid branches. It should not replace an open experiment with an answer key.
Where the reasoning changed
The decisive progress did not come from trying the same payload more times. It came from changing what counted as evidence. The sequence below is ordered by reasoning milestone, not by elapsed time or spend.
-
Hypothesis
Turn public incident clues into a testable application path
Public clues narrowed setup and search, but treated one inferred mechanism with too much confidence.
Rejected · 06:12The direct authorization model remained blocked under runtime testing.
-
Real primitive
Reach security-relevant unauthenticated application control
The experiment established a meaningful capability even though the full impact claim was still open.
Closed · 06:19Dynamic page compilation was unavailable in the stock runtime. Closed · 06:20The custom-program path remained disabled by an empty allowlist.
- False summit Reject a real marker produced through an attacker-invalid step Local feature enablement and a service restart broke remote-attacker ownership of the chain.
-
Proof reset
Preserve receipts and dead ends, then raise the causal gates
The next run inherited setup facts, forbidden local mutations, repeat requirements, and a fixed-build control.
Corrected · 06:36An omitted redirect in session bootstrap explained intermittent results; the state change was revalidated.
- Breakthrough Abandon the original mechanism after code and runtime evidence disagreed A different trust-boundary failure composed with stock server behavior supplied the missing remote edge.
- Accepted proof Return service-account command output through the application Two clean vulnerable replays succeeded; the unchanged fixed replay did not, while the benign control remained reachable.
The trajectory preserves the changes in the agent’s model rather than only its final answer. At 06:12 UTC it explicitly rejected its first authorization model after the direct path remained blocked. At 06:15 it observed the cross-page trust mismatch and the first unauthenticated state change. It then closed two tempting execution routes because the stock runtime had disabled dynamic JSP compilation and kept custom programs behind an empty allowlist. At 06:36 it traced intermittent results to a missing redirect in its own session bootstrap, corrected the harness, and revalidated the state change. The two component primitives were recorded at 07:32; their repeated composition was recorded at 07:40; the independent judge accepted the proof at 07:44.
Reasoning is not proof. These persisted reasoning milestones explain why the agent changed course; they do not establish impact. The impact claim is anchored separately in the repeated runtime receipts, unchanged fixed-build control, artifact closure, and accepted typed verdict below.
- Model falsifiedThe obvious direct path was still access-controlled.
- Boundary foundA two-page trust mismatch produced the first remote state change.
- Easy sinks closedRuntime and allowlist controls invalidated two apparent execution routes.
- Harness correctedIntermittence came from session bootstrap, not the target primitive.
- Primitives storedTwo runtime-observed capabilities were committed to durable knowledge.
- Proof acceptedRepeated composition and the fixed control passed independent review.
Accepted runtime evidence
The second run used official PaperCut NG installers for the exact tested versions and builds. The accepted run included one authenticated editor render after ordinary setup, then restricted every security-relevant state change to new, unauthenticated remote application requests. A separate fresh-container replay later omitted the editor render and still reached the same positive and negative controls, removing it from the required preconditions.
At the vulnerability-class level, the accepted chain combined an authorization failure with unsafe server-side interpretation. The first let an unauthenticated client influence application state reserved for a privileged workflow. Stock application behavior later consumed that state under the PaperCut service identity. This supplied the remote causal edge that the first experiment lacked.
The result reached operating-system command execution as the PaperCut service account. The output was retrieved over HTTP through the target application, rather than inferred from a file inspected inside the container. The complete script succeeded twice from fresh state.
Six causal edges in the accepted chain
The accepted chain contains six causal edges. Each one was established by runtime evidence rather than inferred from the final command marker.
- 01Remote clientStarts without an authenticated application session
- 02Authorization failureInfluences application state reserved for a privileged workflow
- 03Server-side statePersists through stock application behavior
- 04Unsafe interpretationThe application consumes attacker-influenced state in its service context
- 05Service executionAn operating-system command runs under the PaperCut identity
- 06Remote receiptCommand output returns through the application over HTTP
The important result is the composition, not any one object in it. The first run had reached the last visible effect only after local operator intervention. The accepted run connected all six edges with remote application evidence, then reproduced the same sequence from another clean reset.
The remote receipt
The accepted evidence is more concrete than a success flag. The remote client received command output containing the effective service identity from both vulnerable replays. The normalized receipt retains the HTTP status, service identity, and control outcome:
uid=1001(papercut) gid=1001(papercut)uid=1001(papercut) gid=1001(papercut)command receipt absentrelated product feature remained activeThe proof client retrieved the receipt over the application network boundary. The attacker sequence contained no Docker file copy, no target-side command, no feature enablement, and no service restart. Before the second successful replay, the target was reset to its pre-attack product state.
The build identity was equally controlled. All targets came from official Linux installers: PaperCut NG 25.0.11 build 75758 for the vulnerable target, 25.0.12 build 76497 for Emergency Patch Release 1, and 25.0.12 build 76510 for Release 2. No product binaries were patched to create the result.
The variant stage replayed the unchanged request sequence against Release 1. It produced no command effect, but discovered that a residual unauthenticated configuration change still landed. That was a real fix bypass at the authorization layer, bounded to configuration modification rather than inflated back to RCE. The same frozen scripts were then replayed against Release 2. Across eight attempts, the unique sentinel remained unset, related settings remained at their defaults, neither tested file-write form produced its expected file, and the command receipt returned 404. The unchanged vulnerable control still returned the PaperCut service identity, showing that build 76510 changed the tested target behavior rather than merely breaking the harness.
Why the deterministic variant script matters
Patch validation should not require rediscovering the bypass from scratch. Once the Release 1 residual was confirmed, Pruva froze the variant’s request sequence, state checks, cleanup steps, remote receipt, and benign control into a deterministic script. For the Release 2 test, the product build changed; the attack input and evidence collection did not.
The legacy wrappers did not exit cleanly on Release 2. Their terminal assertions encoded Release 1’s later rejection point, while Release 2 blocked the sequence earlier and therefore never produced that expected message. We treated those exits as a stale oracle, not as proof of a target or infrastructure failure, and evaluated the unchanged state, absent files, HTTP receipt, target identity, and still-positive vulnerable control directly.
That distinction made the second patch boundary straightforward to evaluate:
- the vulnerable build remained positive, proving that the harness could still observe the chain;
- Release 1 still reproduced the residual state change, preserving the variant’s positive control;
- Release 2 left the sentinel and related settings unchanged across eight attempts; and
- the same remote command receipt remained absent while the surrounding product behavior stayed available.
The result is more useful than an agent independently failing to rediscover the path on a new build. It creates an unchanged regression input that can be replayed against a candidate fix, a release build, or a later maintenance update. It does not prove that no other bypass exists; it proves that the exact measured Release 1 variant no longer reproduced on build 76510 under the frozen test conditions.
The evidence supports a deliberately bounded statement:
| Question | Result |
|---|---|
| Did an unauthenticated remote request sequence reach code execution on tested 25.0.11 after normal setup? | Yes, twice in the accepted run and again in a fresh replay |
| Did the effect execute as the PaperCut service identity? | Yes |
| Was command output observable through the remote application boundary? | Yes |
| Did the unchanged sequence produce the effect on either tested 25.0.12 build? | No |
| Did Release 1 remove every measured primitive? | No; the residual unauthenticated state change still reproduced |
| Did the Release 1 residual reproduce on Release 2 build 76510? | No; eight attempts left the sentinel and related settings unchanged |
| Was a prior authenticated editor render required? | No; a fresh-container replay passed after normal setup without it |
Learning and return on spend
The second experiment did not start from zero. It preserved installer identities, known-good setup steps, the reachable Card/ID surface, and branches already disproven by runtime evidence. That transfer happened through the revised ticket, not an automatic exact-run memory hit. The attached learning context contained five unrelated references and did not retrieve the first PaperCut run. Every inherited fact still had to be revalidated.
That transfer changed where the next run spent its search. It no longer paid to rediscover the laboratory or repeat dead ends; it could concentrate on the causal edge missing from the first proof.
After the runtime proof, the agent stored two component capabilities and one composed capability as durable exploit knowledge. Each record names its target build, evidence strength, source run, and supporting receipts.
Memory correction. One component record included the editor-render condition observed in the accepted run. The later cold replay disproved that requirement. The evidence ledger preserves both states, and future retrieval must pair the historical capability with the corrective cold-start evidence rather than silently inheriting the superseded precondition.
The economics reflect that transfer. The first Kimi K3 investigation cost USD 48.75 and returned useful primitives plus an invalid command-execution claim. The second cost USD 27.17 and returned the accepted remote proof, two clean repeats, the fixed-build control, and bounded follow-up analysis. These are provider-accounted totals grouped by the role that incurred them: primary investigation, follow-up analysis, separate verification, and setup or evidence processing.
- Primary investigation
- Follow-up analysis
- Independent verification
- Setup and evidence processing
- Total spend
- 44% lower
- Provider-billed model requests
- 600 to 451
- Agent active time
- 3h 38m to 2h 44m
- Primary investigation
- 54% lower
Token consumption: less repeated context, not better cache reuse
Provider usage receipts make the cost difference more concrete. The accepted workflow used 48.5% fewer input tokens and 21.0% fewer output tokens, even though it also completed a 102-request follow-up variant analysis. The reduction came from 149 fewer model requests and less context carried through the workflow.
- Cached input read
- Uncached input
| Metric | First | Accepted | Change |
|---|---|---|---|
| Total input | 125.64M | 64.68M | -48.5% |
| Cached input | 123.71M | 63.45M | -48.7% |
| Uncached input | 1.92M | 1.24M | -35.7% |
| Output | 328.6K | 259.6K | -21.0% |
| Cache-read share | 98.47% | 98.09% | -0.38 pp |
Both workflows already reused cached context heavily. Cache-read share stayed near 98% rather than improving, while cache writes fell from 179.0K to 87.7K tokens. The accepted run was more efficient because it avoided requests and context growth, not because its cache hit rate was higher. Reasoning tokens reported by providers are included in output totals and are not counted again.
The primary reproduction agent in both investigations used Kimi K3. That holds the principal investigation model constant, but the whole-workflow totals also include support, verification, claim-matching, and learning requests. This is an experiment-design comparison, not a model benchmark.
From exploit proof to a defense package
A security report can describe what happened. A deterministic reproduction can ask whether a defense observes or prevents the same behavior.
The accepted script therefore provides a repeatable attack input for defense work.
The first validated hunting layer starts with PaperCut’s published indicators. Two narrow application-log hunts were replayed against preserved evidence:
- a Card/ID lookup hunt matched four attack events in the vulnerable replay; and
- a patched-runtime rejection hunt matched two blocked attempts in the controlled replay.
Validated scope. Neither hunt matched the benign fixed-build Card/ID control. That is useful retrospective coverage. It does not imply that any endpoint or network prevention control has been validated.
Validated now: application-log hunts
The two application-log rules start from PaperCut’s published indicators and observable log
behavior. Sigma is a portable detection-rule format; these rules express the required application
message fields without embedding the exploit request. Across the preserved corpus, the first rule
matched all four labeled vulnerable query events and the second matched both labeled
patched-runtime block events. Neither matched the benign fixed-build control. An ordinary card
lookup, a VALUES/CAST string without the Card/ID error prefix, and an exception-only block line
also remained quiet.
They remain experimental Sigma rules. PaperCut server.log is not a universally standardized
Sigma source, so each deployment must map its raw message field to message and confirm that log
multiline handling does not split the indicator.
title: PaperCut Suspicious External Card Lookup Query Material
id: a7d75aae-9bd5-4c0d-96e0-e66c9ebc40fd
status: experimental
logsource:
category: application
product: papercut
detection:
selection_lookup:
message|contains: 'Database error looking up cardID:'
selection_query_value:
message|contains:
- 'VALUES(CAST('
- 'VALUES CAST('
condition: selection_lookup and selection_query_value
falsepositives:
- Authorized testing of a custom external Card/ID lookup integration
level: high
tags:
- attack.initial-access
- attack.t1190
title: PaperCut Blocked Unsafe External User Lookup SQL
id: f0de3dd2-c0ae-43ec-a5ea-9b3717e56dc8
status: experimental
logsource:
category: application
product: papercut
detection:
selection_lookup:
message|contains: 'Error occurred looking up external user with card:'
selection_block:
message|contains: 'Unsafe external user lookup SQL blocked'
condition: selection_lookup and selection_block
falsepositives:
- Administrator testing a legacy external Card/ID lookup configuration after patching
level: high
tags:
- attack.initial-access
- attack.t1190
For collectors that ingest server.log as raw text, the ordered-text validation used these
extended regular expressions. They are separate raw-log tests, not one-to-one translations of
Sigma’s field conditions:
- Query-shaped Card/ID lookup
Database error looking up cardID:.*VALUES[ (]+CAST\(- Patched unsafe-lookup block
Error occurred looking up external user with card:.*Unsafe external user lookup SQL blocked
The laboratory’s benign card value is not a production exclusion. It proves the frozen test corpus stayed quiet; converting one test value into a global suppression would create an avoidable blind spot. Adapt regex syntax to the target SIEM and retain the complete raw event for investigation.
Elastic’s endpoint detections add two complementary views
Elastic has since published two production detection rules for the public campaign behavior. The
cross-platform Java class-file creation rule
looks for new or overwritten .class files under PaperCut server library paths. The Windows
suspicious child-process rule
looks for shells, discovery tools, download utilities, and related children of PaperCut server
components.
Those rules complement, rather than replace, Pruva’s validated application-log hunts. The log rules
cover the application-side lookup and patch-block behavior in our frozen corpus; Elastic’s rules
cover filesystem and process effects reported in the active campaign. Elastic labels both rules
production. Pruva has not independently replayed those endpoint rules, so we do not present them
as part of our validated two-rule count.
What defenders should do now
The research result does not supersede PaperCut’s guidance. Operators should restrict Application Server access to trusted addresses, install Emergency Patch Release 2 or a newer fixed build even if Release 1 is already present, and investigate exposed systems immediately rather than waiting for evidence that their own environment was targeted.
Preserve Application Server logs and investigate unexpected PaperCut child processes, new class files under server library paths, the Card/ID and JDBC errors listed in the bulletin, and missing or truncated logs. A blocked response or absence of one published indicator does not prove that no side effect occurred; correlate application, process, filesystem, and network evidence.
The larger lesson is not specific to PaperCut. A marker is evidence of an effect. It is not evidence that the claimed attacker caused that effect through the claimed path. The first run became useful only when we preserved what it genuinely proved, rejected what it did not, and made the next experiment harder to fool.