The Stardew malware scanner is a semi-automated app which detects new mod downloads, scans them for potential malicious code, and assesses flagged mods using agentic AI with human review.
This README is for human users. See AGENTS.md instead. Do not read this file unless specifically
instructed to do so.
This is a late line of defense against malware in the Stardew Valley modding community. In particular, it detects malicious code that can't be detected by the antiviruses used by mod sites like Nexus Mods.
At a high level, the scanner produces scan results from the Stardew mod dataset. Each scan result covers a single download, with three parts:
- Metadata about the download. That includes file info (e.g. file sizes and detected types), assembly info (e.g. code signatures and file hashes), decompiled code layout, etc.
- Detections which flag code or files for review based on deterministic rules. These cover APIs and functionality which can be used maliciously (e.g. networking or processes), techniques which allow bypassing security checks (e.g. code emitting), and signs of potential malicious intent (e.g. obfuscation).
- An assessment which investigates each detection, documents what the code is doing, and decides whether the download is safe or malicious.
The overall workflow looks like this:
- The
scanCLI tool automatically:- finds unscanned downloads in the Stardew mod dataset;
- decompiles compiled .NET code;
- scans the metadata & decompiled files;
- and produces a JSON scan result file with any detections found.
- The user:
- assesses scan results with detections, either manually or using agentic AI;
- saves the assessment to the scan result;
- and handles malicious findings as needed.
This is one part of three interrelated repos:
| repo | visibility | contains |
|---|---|---|
| Stardew mod dataset | public | The general metadata about Stardew Valley mods and downloads. |
| Stardew malware scanner (this repo) |
public | The malware scanner which produces scan results from the Stardew mod dataset. |
| Stardew malware scanner data | private | The scan results produced by the malware scanner, and their assessments. This repo is sensitive and invite-only. |
Mods are assessed for potential malware by Pathoschild and other volunteers. Discussion and coordination happens in a private Discord channel (see the private volunteer resources).
This channel is invite-only, since it includes sensitive discussions (e.g. malware techniques and how we detect malware authors) and can name legitimate mods/authors during investigation (which could cause reputational damage if those investigations appeared when players search for the mod/author).
Feel free to contact Pathoschild for access if:
- you're interested in discussing or helping with the project or mod malware in general;
- and you're an established mod author, or well-known member of the Stardew Valley or security community, or official representative of an established mod site, etc.
This project isn't feasible without using AI, for a few reasons:
- This is meant to catch malware that existing deterministic security checks don't catch. That means reviewing mod code to understand what it's doing, not only checking for known malware patterns which new malware can just avoid.
- The number of mod downloads created each month now far exceeds human volunteers' ability to do that manually, especially with AI-generated mods.
- The scanner is open-source, so malware authors can code against the public deterministic rules. (We could make the scanner private instead, but that significantly weakens it since others couldn't help improve the scanner.)
As a result, this project does include AI in the workflow. However:
- AI is always optional. The whole workflow can be entirely handled by human volunteers (if we have enough volunteers to cover the number of downloads created each month).
- AI is used to the least extent required. Most of the scanner is deterministic code; AI is only used to help humans with assessing flagged downloads and assemblies.
- AI is never trusted on its own. A scan result assessed with AI is considered non-authoritative, unless that assessment was reviewed and confirmed by a human.
- All AI features are vendor-agnostic, so they can be used with any AI provider (including self-hosted or local-only models).
- The deterministic portions of the scanner are routinely improved based on AI output. For example, if AI is repeatedly reporting a particular pattern in malicious code, that pattern can then be added to the deterministic rules to further reduce dependence on AI.
- Set up the dataset:
- Clone the Stardew malware scanner data repo.
- Download the full Stardew mod dataset, including mod download files.
- Run this PowerShell script or equivalent to link up the folders (edit the
#configuresection as needed):Note: if you don't have access to the data repos, you can also just create empty folders instead. The scanner will recreate fresh scan results for all detected downloads.# configure $modDatasetRepo = "C:\source\Pathoschild.StardewModDataset" $scannerDataRepo = "C:\source\Pathoschild.StardewMalwareScanner.Data" # add symlinks $type = if ($env:OS -eq 'Windows_NT') { 'Junction' } else { 'SymbolicLink' } New-Item -ItemType $type -Path data/archived-scan-results -Target "$scannerDataRepo\archived-scan-results" New-Item -ItemType $type -Path data/scan-results -Target "$scannerDataRepo\scan-results" New-Item -ItemType $type -Path data/StardewModDataset -Target $modDatasetRepo
- Set up the SMAPI toolkit:
- Install the game and SMAPI.
- Edit
src/Directory.Build.propsto correct your game path if needed.
- (Optional) Configure the AI API you'll use to assess downloads. You can skip this if you'll use a chat-based AI or
won't be using AI.
-
Copy
src/StardewMalwareScanner/appsettings.jsonctoappsettings.local.jsonc. -
Add one or more entries under
ApiProviders(see the commented-out examples in that file).The available fields are:
field usage ClientThe API client and wire format. The supported options are Anthropic(e.g. for Claude) andOpenAI(used by most other providers).ApiKeyThe API key used to call the API. DefaultModelThe default AI model ID to use when calling this API, when not overridden via --model.Endpoint(Optional) The base URL for the API (if supported by this client), or nullfor the client's default. This is only supported by theOpenAIclient; specify if you're calling an OpenAI-compatible endpoint from another vendor like OpenRouter. Default none.MaxTurnsPerDownload(Optional) The max tool-calling turns to allow per download before giving up on it, as a safety net against a runaway loop. Note that each turn can incur exponential token costs (due to the entire context from previous turns being prepended), so you should be careful setting this to a higher value. Default 20. MaxPreloadSize(Optional) The target max size for the initial content sent to the AI when assessing a download, in characters (default 700,000). That limit includes the scan result, directory listings, and the mod files to assess. It does not include the system prompt, or any tools the AI calls.
If the preloaded content exceeds the limit, the largest files are reduced to excerpts around the detected code as needed until the content fits. If the content can't be compacted any further and is still over the limit, the maximally compacted form is sent even if it's over the limit.
This value is a tradeoff:
- It should be as high as possible so the AI can see all the info needed at once. (If the limit is higher than needed, the preloaded content is just sent as-is.)
- It should be low enough to leave room for the AI's processing and tool uses (e.g. reading more files) within its available context window.
- Note that this is measured in characters (not tokens), and decompiled C# code tends to be denser in tokens than normal English text.
The specific tuning depends on each AI (e.g. how it tokenizes content, how many turns it needs, etc). A good starting point is ~50% of the AI's token context window. For example, for an AI with 1.4 million token context window, start with 700K and adjust based on the token usage reported after each conversation.
-
-
Update the Stardew mod dataset if needed.
-
Run the scanner through a terminal:
cd src/StardewMalwareScanner dotnet run -- scanRun
dotnet run -- scan --helpto see the available options.(You can also launch the project through Visual Studio with debugging, which will default to
scan.) -
Optionally, update the trusted assemblies list for new common dependencies (e.g. NuGet packages).
-
Before assessing C# mods, run the
decompileCLI tool so the decompiled code is available:cd src/StardewMalwareScanner dotnet run -- decompileThat will decompile all mods. That may take a while the first time you run it, and uses ~1GB of space in the repo's
data/cachefolder.You can also run it for a specific mod you want to assess. For example:
dotnet run -- decompile --site Nexus --modPageId 1915
-
Then apply one of the three flows to assess scan results.
-
Assess manually:
See the assess manually doc. -
Assess using chat-based AI:
You can prompt a chat AI in this repository with a message like:Assess the latest unassessed download with critical detections uploaded in the last 30 days.
When assessing multiple downloads, you can reduce token costs by using a separate AI subagent for each download (so the files read for each assessment don't accumulate in the main chat context). This also avoids cross-referencing in assessment text (e.g. "similar to Mod X, this download…"). For example:
Assess the 10 latest unassessed downloads with critical detections uploaded in the last 30 days. Create a separate subagent for each download. Use a minimal prompt which only states the task and points to the
docs/ai/assess.mdfile. -
Assess using API-based AI:
You can use theassesscommand-line tool to assess downloads using an AI model API (e.g. the Anthropic API or an OpenAI-compatible API like OpenRouter). This is more reliable for bulk assessments, and can be called programmatically.However:
- You need an API key for the AI provider (unless it's a local model), which usually costs money. For the Anthropic API, note that API keys are not included in Claude subscription plans.
- The API providers must be configured. If you configure multiple providers, specify which to
use with
--use <name>.
For example, let's say you configured a 'Claude' provider. To assess the ten latest downloads uploaded after a given date with high- or critical-severity detections:
dotnet run -- assess --use Claude --minSeverity High --minDate "2026-06-01" --verbosity LowRun
dotnet run -- assess --helpfor the available options.
-
- The command line interface has tools for scanning, searching, and assessing downloads. This is the main way of interacting with the scanner and scan results.
- Handling malware covers what to do after a download is assessed as malicious.
- Sideloading lets you scan and assess an arbitrary mod download that's not part of the Stardew mod dataset.
- Verifying trusted assemblies covers marking third-party assemblies as safe, so they don't need to be decompiled and scanned for each mod download that bundles them.
This app can detect most malicious mods, but a sufficiently motivated malware author can circumvent any security scans.