Peakstone
Browse plugins
Sell on PeakstoneHow selling works
FeesWhat authors pay
Start selling
HelpCancelling, payments and refunds
Licence SDK docs
Your account
Terms
Privacy
Home
Sign inWe email you a sign-in link
Copy page link

Releases and the jar scanner

How uploaded jars are scanned, what the scanner looks for and what its verdicts mean.

Uploading a release

Jars are optional on paid listings and required on free ones. Open the Releases tab of your listing, choose the file and give it a version such as 1.4.2.

  • The file must be a real zip and at most 50 MB.
  • The version is letters, digits and . - + _, up to 32 characters, and unique among the releases that were not rejected.
  • Notes of up to 500 characters are optional.

Peakstone stores the file with its SHA-256, runs the scanner and puts the release in the review queue. Subscribers can download a release only after a reviewer approves it. Each release shows its review status on the Releases tab, and you can always download your own files.

The jar scanner

Every upload is checked by peakstone-scan, a static scanner written in Rust that looks for malware and backdoor indicators. It reads class files and archive entries; it never runs anything, never extracts to disk and never trusts a size field from the archive.

Every finding says where (path) and why (detail and evidence), so a reviewer can confirm or dismiss it quickly. If the scanner is unavailable or fails, the upload still goes through and the release is stored without a report; it is reviewed by hand either way.

Verdicts and score

Each finding has a severity worth a number of points. The score is the sum over all findings, capped at 100, and the verdict follows from it.

SeverityPoints
Critical60
High25
Medium10
Low3
Info0
VerdictWhen
MaliciousAt least one critical finding
SuspiciousScore of 40 or more
ReviewScore of 10 or more
CleanAnything lower
ErrorThe file could not be read as a zip

Because the score is a plain sum, several findings of the same rule add up. A large library jar with a few native-code and process findings can reach suspicious. That is the intended signal that a human should look, not an accusation. Only a critical finding means malicious.

What it checks

Class rules combine facts within a single class, which keeps false positives low. The main ones, with their usual severity:

RuleSeverityWhat it looks for
known-malwareCriticalPublic indicators of known campaigns such as fractureiser, and operator-backdoor chat triggers in a class that also grants operator status.
op-backdoorCriticalGranting or removing operator status from a chat or command event. Medium without the event.
token-grabberCriticalPaths used by credential stealers, such as browser and launcher token stores.
remote-class-loadingHighDefining classes at runtime. Critical when the same class also downloads and decodes data.
process-execHighRunning operating-system processes.
console-dispatch-from-chatHighDispatching commands from chat events or as the console.
native-codeMediumLoading native libraries, or shipping .so, .dll and similar files.
discord-webhookMediumA complete Discord webhook URL embedded in the code.
script-engineMediumUse of javax.script.
hardcoded-ipLowPublic IPv4 addresses in string literals.
unsafeLowReferences to sun.misc.Unsafe.

It also checks the archive and the plugin descriptor:

  • Zip bombs (critical): too much uncompressed data, too many entries or an extreme compression ratio. Nothing is decompressed once this trips.
  • Path traversal (high): absolute entry names or .. segments.
  • Hidden class files and disguised archives, encrypted entries and duplicate entry names that hide each other.
  • Obfuscation: jars whose class names or strings are mostly meaningless or encrypted-looking, which a reviewer then reads more closely.
  • The descriptor (paper-plugin.yml, plugin.yml, velocity-plugin.json or bungee.yml at the jar root): missing or unparsable, or naming a main class that is not in the jar.
  • Nested jars are scanned to a limited depth (2 by default).

Findings are sorted by severity, and the same rule on the same path is reported once. At most 500 are listed; the score and the verdict are computed before that cut.

Shaded libraries

Widely shaded libraries legitimately trip some rules: bStats and SQLite probe the operating system, Netty and Guava use Unsafe, dependency loaders download jars. The scanner knows a list of these and lowers only the rules each one legitimately triggers, usually to info. The match works on relocated copies too, such as com/author/plugin/libs/org/bstats/.

What it cannot do

  • It is static and works on one class at a time. Strings assembled or decrypted at runtime are not followed, which is why obfuscation is flagged.
  • Native code is flagged, not analysed.
  • Only the constant pool is read, not bytecode, so a class that references an API shows up even if the call is never reached.
  • Its indicator list is short and curated. That is why every release is also looked at by a person.

The source and the full rule list are in scanner/ of the Peakstone repository. To list a plugin, start with Getting started as an author.

Report format

The scanner prints one JSON object. Peakstone stores the verdict, the score, the first 200 findings and the detected plugin descriptor with the release, and the reviewer sees them in the queue.

Scan report (shortened)
{
  "scanner": "peakstone-scan",
  "verdict": "review",
  "score": 10,
  "plugin": { "kind": "paper", "name": "MyPlugin", "version": "1.4.2", "main": "com.example.myplugin.MyPlugin" },
  "findings": [
    {
      "rule": "native-code",
      "severity": "medium",
      "path": "libs/natives.jar!/lib/native.so",
      "detail": "...why, in a sentence",
      "evidence": "the literal trigger"
    }
  ]
}