The Modrinth Store addon handles:
- External API calls to Modrinth (api.modrinth.com): user-controlled search queries, project IDs, version IDs
- File downloads from Modrinth CDN: mod files, modpack archives, override files
- File uploads to game servers via the panel's daemon: writes files to server directories
- User input: search queries, server IDs, project/version IDs, admin settings
- Database operations: cache storage, installation records, settings
- All routes require session authentication via
security.requireAuth()applied at the router level - Admin routes (config, cache clear, statistics) additionally check
user.isAdmin - Server ownership verified before install/uninstall operations. Users can only modify their own servers (admins can modify any).
- Admin sidebar item hidden from non-admin users via
isAdminItem: true
- All mutating routes (POST, DELETE, PUT) use
security.requireCsrf()middleware - GET routes are exempt (stateless reads)
- CSRF token provided by the panel's
csrfProtectionmiddleware via Double Submit Cookie pattern
| Input | Validation |
|---|---|
| Search query | Max 200 chars, stripped of <>"';` |
| Project/Version ID | Regex: ^[a-zA-Z0-9_-]{1,64}$ |
| Server ID | UUID or numeric format only |
| Offset | Non-negative integer |
| Limit | Clamped to [1, 50] |
| Sort index | Whitelist: relevance, downloads, follows, newest, updated |
| Project type | Whitelist: mod, modpack, resourcepack, shader, datapack, plugin |
All file paths pass through security.sanitizePath(baseDir, userPath) which:
- Resolves the path to an absolute path using
path.resolve() - Attempts
fs.realpathSync()to resolve symlinks - Verifies the resolved path starts with
baseDir + path.sep - Returns
nullif the path escapes the base directory
Enforced in:
DaemonClient.uploadFile()- destination pathDaemonClient.deleteFile()- file pathDaemonClient.mkdir()- directory pathDaemonClient.listFiles()- directory pathInstaller.installModpack()- override file pathsInstaller.uninstallMod()- file deletion path
All external URLs validated via security.validateUrl(url, allowedDomains):
- Protocol must be HTTPS. No HTTP, no file://, no data:
- Domain must be in allowlist. api.modrinth.com, cdn.modrinth.com, modrinth.com
- Applied to all Modrinth API calls, all file downloads, all project links
All Modrinth API responses validated against Zod schemas before use:
ModrinthSearchResponseSchema- validates search resultsModrinthProjectSchema- validates project dataModrinthVersionSchema- validates version data
Schema validation failures throw ZodError which is caught and logged (not retried).
- No raw SQL with string interpolation. All database operations use
$executeRawtagged template literals or$queryRawwith parameterized values. - Migration SQL validated. Addon migrations checked against
ALLOWED_MIGRATION_SQLregex before execution (only CREATE TABLE, CREATE INDEX, ALTER TABLE, DROP allowed). - Rollback SQL validated. Same regex check on downgrade migrations.
- EJS
<%= %>auto-escapes. All dynamic content in templates uses escaped output. - Server-side markdown rendering. Project body rendered server-side (not injected via
<script>tag). - No
innerHTMLwith user data. Progress/error messages usetextContentin client-side JS. escapeHtml()/escapeJsString()utilities available for any raw output needs.
- Modrinth API rate limits handled via
Retry-Afterheader parsing - 429 responses trigger exponential backoff (not immediate retry)
- Request timeouts: 15s for API calls, 60s for file downloads, 30s for daemon requests
- No CDN scripts without SRI. All external scripts (if any) must have integrity hashes.
- Dependencies audited. Minimal dependency tree (adm-zip, zod).
- No
npxexecution. Tailwind build uses local binary.
- In-memory progress tracker. Progress data lost on addon restart (acceptable for UX).
- SQLite cache. Not shared across panel instances (single-instance deployment only).
- No file size limits on downloads. Large modpacks could consume memory (mitigation: streaming where possible).
- Client-only mod detection. Heuristic-based (list of known client mods), may miss some.