{"id":19764083,"url":"https://github.com/rikonardo/pluginscan","last_synced_at":"2026-02-26T08:02:58.822Z","repository":{"id":65017056,"uuid":"497706718","full_name":"Rikonardo/PluginScan","owner":"Rikonardo","description":"Minecraft plugin anti-malware scanner","archived":false,"fork":false,"pushed_at":"2022-06-11T19:33:02.000Z","size":226,"stargazers_count":17,"open_issues_count":2,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2023-03-07T15:12:50.173Z","etag":null,"topics":["antimalware","bukkit","bungeecord","bytecode-parser","kotlin","minecraft","paper","scanner","spigot","velocity"],"latest_commit_sha":null,"homepage":"https://scan.rikonardo.com","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Rikonardo.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-05-29T20:50:47.000Z","updated_at":"2023-02-21T06:39:47.000Z","dependencies_parsed_at":"2023-01-12T07:30:25.154Z","dependency_job_id":null,"html_url":"https://github.com/Rikonardo/PluginScan","commit_stats":null,"previous_names":[],"tags_count":null,"template":null,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Rikonardo%2FPluginScan","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Rikonardo%2FPluginScan/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Rikonardo%2FPluginScan/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Rikonardo%2FPluginScan/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Rikonardo","download_url":"https://codeload.github.com/Rikonardo/PluginScan/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":224214059,"owners_count":17274524,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["antimalware","bukkit","bungeecord","bytecode-parser","kotlin","minecraft","paper","scanner","spigot","velocity"],"created_at":"2024-11-12T04:12:19.428Z","updated_at":"2026-02-26T08:02:53.802Z","avatar_url":"https://github.com/Rikonardo.png","language":"Kotlin","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\u003ch1\u003ePluginScan - Minecraft plugin anti-malware scanner\u003c/h1\u003e\u003c/div\u003e\n\n\u003cdiv align=\"center\"\u003e\u003cimg alt=\"Logo\" src=\"logo.png\"/\u003e\u003c/div\u003e\n\n\u003cdiv align=\"center\"\u003e\n    \u003ca href=\"https://github.com/Rikonardo/PluginScan/issues\"\u003e\u003cimg alt=\"Open issues\" src=\"https://img.shields.io/github/issues-raw/Rikonardo/PluginScan\"/\u003e\u003c/a\u003e\n    \u003ca href=\"https://github.com/Rikonardo/PluginScan/releases/latest\"\u003e\u003cimg alt=\"GitHub downloads\" src=\"https://img.shields.io/github/downloads/Rikonardo/PluginScan/total\"\u003e\u003c/a\u003e\n    \u003cimg alt=\"Version\" src=\"https://img.shields.io/maven-metadata/v?metadataUrl=https%3A%2F%2Fmaven.rikonardo.com%2Freleases%2Fcom%2Frikonardo%2Fpluginscan%2FPluginScan%2Fmaven-metadata.xml\"/\u003e\n    \u003ca href=\"https://www.codefactor.io/repository/github/rikonardo/pluginscan\"\u003e\u003cimg alt=\"CodeFactor\" src=\"https://www.codefactor.io/repository/github/rikonardo/pluginscan/badge\"/\u003e\u003c/a\u003e\n    \u003ca href=\"https://discord.gg/zYRTPa3FnQ\"\u003e\u003cimg alt=\"Discord\" src=\"https://img.shields.io/discord/982967258013896734?color=7289DA\u0026label=discord\u0026logo=discord\u0026logoColor=7289DA\"\u003e\u003c/a\u003e\n\u003c/div\u003e\n\n\u003cbr\u003e\n\n\u003chr\u003e\n\n**PluginScan** is a cross-platform java executable analyzer designed to detect malware and other malicious code in Minecraft plugins. It uses Kotlin multiplatform [CafeBabe](https://github.com/Rikonardo/CafeBabe) library to analyze class metadata and detect suspicious patterns.\n\n**❗ Please note that this is not some magic tool that recognizes any malicious code. It recognizes code patterns that can theoretically be used by malicious code, but can also be used for completely legitimate purposes. Also note that the absence of detections of malicious code by the scanner does not guarantee the safety of the plugin, as it can be deceived by complex obfuscation.**\n\nCurrently, PluginScan can be used as **[website](#pluginscan-web)** and **[CLI tool](#pluginscan-cli)**.\n\n## PluginScan Web\nWeb interface is available on [https://scan.rikonardo.com](https://scan.rikonardo.com).\n\nIt is created using Kotlin/JS with React and can be used offline. But we strongly recommend to use a CLI, because it is much faster and more reliable.\n\n## PluginScan CLI\nPluginScan CLI tool is a JVM-powered release of PluginScan. Unlike web version, it allows you to scan multiple plugins at once by passing directory to input. It is also has better way of tracking errors during scanning if they happen.\n\nThis tool requires Java 8+ to run and can be downloaded from [releases page](https://github.com/Rikonardo/PluginScan/releases/latest).\n\nUsage:\n\n```sh\njava -jar PluginScan.jar \u003cinput-file-or-directory\u003e\n```\n\n## Usage as library\nPluginScan also is a Kotlin library that can be used as a dependency in your project. You can install it from maven repository:\n\n```kotlin\nrepositories {\n    maven {\n        url = uri(\"https://maven.rikonardo.com/releases\")\n    }\n}\n\ndependencies {\n    implementation(\"com.rikonardo.pluginscan:PluginScan:1.0.3\")\n}\n```\n\nTo scan jar file, you can use `PluginScan.scan` method. It takes JarFile object and two optional arguments (`sortOutput` and `groupOutput`).\n\nNote that you will need to read jar file by yourself, because currently there is no multiplatform Kotlin zip library. JarFile class is just a wrapper around JarFile list. JarFile is a container for file name inside jar, and it's ByteArray content. You must pass all files from jar, not only classes. Here is an example of PluginScan usage in Kotlin/JVM:\n\n```kotlin\nfun main() {\n    val entries = mutableListOf\u003cJarEntry\u003e()\n    val file = File(\"plugin.jar\")\n    ZipFile(file.canonicalPath).use { zipFile -\u003e\n        val zipEntries = zipFile.entries()\n        while (zipEntries.hasMoreElements()) {\n            val zipEntry = zipEntries.nextElement()\n            if (zipEntry.isDirectory) continue\n            val fileName: String = zipEntry.name\n            entries.add(JarEntry(fileName, zipFile.getInputStream(zipEntry).readBytes()))\n        }\n    }\n    val result = PluginScan.scan(JarFile(entries), groupOutput = true)\n    println(result.reports.size)\n}\n```\n\nNotice that PluginScan relies on file path inside jar, so you need to make sure you pass it in the correct format. Here is an examples of correct path strings:\n\n```\nMETA-INF/LICENSE.txt\nplugin.yml\ncom/example/plugin/ExamplePlugin.class\n```\n\n## Contributing\nThis project was originally meant as a platform, that will be grown by community, so we always welcome any contribution.\n\nYou can easily add your own check by creating class from template below and put it into `com.rikonardo.pluginscan.checks` package.\n\n```kotlin\n@RegisterCheck\nclass MyCheck : Check() {\n\n}\n```\n\nCheck class has 3 overridable methods:\n\n```kotlin\n@RegisterCheck\nclass MyCheck : Check() {\n    override fun before() { }\n    override fun processClass(classFile: ClassFile, fileName: String) { }\n    override fun after() { }\n}\n```\n\nInstance of `Check` class is created for each scan session, `before()` method is called before scan, `processClass()` is called for each class in jar, and `after()` method is called after scan. You can also access all files inside jar at any scan step by accessing `jar` field of `Check` class.\n\nTo report suspicious code, you can use `report()` method.\n\nHere is an simple check, that reports reference to `Player.setOp()` method:\n\n```kotlin\n@RegisterCheck\nclass SetOp : Check() {\n    override fun processClass(classFile: ClassFile, fileName: String) {\n        if (\n            classFile.doReferenceMethod(\"org/bukkit/entity/Player\", \"setOp\")\n        ) report(\n            RiskLevel.MODERATE,\n            \"Plugin can set player's op status\",\n            \"Found setOp method reference\",\n            listOf(ReportEntry.In(className(fileName)))\n        )\n    }\n}\n```\n\nSome useful code, like `className()` which transforms class file name inside jar into java-like class name, `ClassFile.doReferenceMethod()` which checks if class file references given method, and many other useful methods are located in `com.rikonardo.pluginscan.checks.utils` package.\n\nNow just fork this project and start coding! Then create pull request and we will merge it into master.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frikonardo%2Fpluginscan","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frikonardo%2Fpluginscan","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frikonardo%2Fpluginscan/lists"}