Repository navigation
fix(security): address security audit findings - #50
Merged
Merged
Conversation
- derive the key from the submitted panic password, not the stored hash - use a fresh random IV per encrypted value (iv:ct:tag) - run encrypt and restore in a single transaction, never half restore - keep decrypting the legacy shared-IV format for existing instances - rate limit encrypt and the public restore endpoint - drop the API-key admin guard that allowed anonymous access outside production Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- read isAdmin/isModerator/isBanned from the DB on every request instead of trusting the sealed session cookie - bound session lifetime (7 days) and set secure cookies in production - honour proxy IP headers only from trusted proxies (TRUSTED_PROXIES) - consume login challenges and PoW atomically, compare proofs in constant time - stable fake salts and identical errors to stop username enumeration - rate limit login and registration - make registration atomic: one invite per account, single first admin - keep the tracker passkey out of the client session, read it from the DB - gate torrent downloads on approval, make the debug torrent endpoint admin only - moderators can no longer ban or unban moderators, block removing the last admin - escape LIKE wildcards in searches, hide raw IPs from moderators - refuse the placeholder IP_HASH_SECRET in production Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- sanitize torrent descriptions (marked output) with DOMPurify before v-html - sanitize admin rich text (branding, homepage) server side with sanitize-html - never return the raw .torrent blob in JSON, strip uploader announce URLs on upload - hide pending torrents from non-owners in details, uploads and downloads - require a session or passkey for RSS feeds, list approved torrents only - escape CDATA terminators in RSS and Torznab descriptions - sandbox uploaded files (SVG) with CSP, block path traversal on logo/favicon cleanup - require login for forum reads, cap unbounded forum queries - limit torrent upload size, validate description, category and tags - authors can no longer delete topics with replies from others - await rate limiters that were silently never applied Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- cap credited upload/download by elapsed time (TRACKER_MAX_RATE_MIBPS) - credit no upload when the swarm has no other leecher, ignore non-finite counters - bind Redis peer entries to their owner so peer_id reuse cannot skew or evict - refuse announces on pending torrents except for the uploader and staff - stop trusting left=0 to bypass the minimum ratio without a real snatch - require a passkey and explicit info_hash for scrape, report approved torrents only Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- npm update + npm audit fix: 71 -> 28 advisories, none left in runtime code (h3, nitropack, nuxt 4.6, vue 3.5.43, ws, drizzle-orm, tiptap, devalue, defu) - drop stub @types/marked and @types/uuid, both packages ship their own types - node 20 is end of life: use node 22 in the Docker image and docs workflows Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- generate a random Grafana admin password instead of admin/admin - fail fast in compose when DB, Redis, session, IP hash or Grafana secrets are unset - bind Postgres, Redis, Prometheus and Grafana to localhost in dev/local/loadtest compose - disable tracker X-Forwarded-For trust where the tracker port is published directly - strip passkey/apikey query params from Caddy access logs - mask credentials when db-push prints the database URL - stop interpolating PR branch names in release workflow scripts, validate the version - untrack pgbouncer userlist.txt (ship an example), drop the unused admin API key Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- health check no longer returns raw database/redis error messages - grafana password endpoint logs upstream errors instead of returning them - reject only deletes pending torrents and bounds the reason Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Important Review skippedToo many files! This PR contains 104 files, which is 4 over the limit of 100. To get a review, reduce the PR to 100 files or fewer by splitting it into smaller PRs or changing its base branch. Upgrade to a paid plan to raise the limit. This review couldn't start because sufficient usage credits or metered capacity aren't available. Add credits or update usage-based reviews in the billing tab, then retry. ⚙️ Run configuration
⛔ Files ignored due to path filters (1)
📒 Files selected for processing (104)
You can disable this status message by setting the
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Security audit fixes, one commit per area. Unit tests 80 → 109 passing, production build passes.
Critical
fix(panic))ADMIN_API_KEYguard is removed. It allowed anonymous encryption wheneverNODE_ENV != production, and returned 503 in production.fix(content))marked→v-html) are now sanitized with DOMPurify.Auth / authorization (
fix(auth))securein production.TRUSTED_PROXIES). Before, IP bans and rate limits could be bypassed by spoofingX-Forwarded-FororCF-Connecting-IP.Data leaks (
fix(content)).torrentblob (which carried the uploader's passkey) is no longer returned in JSON. Announce URLs are stripped on upload.?passkey=and only lists approved torrents. The CDATA terminator is escaped in RSS and Torznab.rateLimit()calls that were never awaited are now awaited.Tracker (
fix(tracker))TRACKER_MAX_RATE_MIBPS, default 100). Nothing is credited when there is no leecher.peer_idcan no longer skew another user's stats.left=0no longer bypasses the minimum ratio without a real snatch.info_hashvalues. Full scrape is disabled.Other
fix(invites): creating more invites than allowed is no longer possible.build(deps):npm update+npm audit fix.fix(infra):admin.release-tag.ymlis fixed.userlist.txtis no longer tracked.fix(api):/api/healthno longer returns internal errors.rejectonly deletes pending torrents.Deployment notes
NUXT_SESSION_PASSWORD. Old cookies have no expiry and still contain the passkey.TRUSTED_PROXIES,TRUST_CLOUDFLARE,TRACKER_TRUST_PROXY,TRACKER_MAX_RATE_MIBPS(see.env.example).IP_HASH_SECRET: in production, a value that is the placeholder or shorter than 32 characters makes IP hashing throw.admin.?passkey=;ADMIN_API_KEYis gone.Not addressed
completed.unsafe-inline.noUncheckedIndexedAccessis enabled. The typecheck now reports 33 errors instead of 25. They are on lines that already existed, and typecheck is not run in CI.Test plan
npx vitest run: 109 passing, with new tests for panic crypto, client IP, sanitizers, tracker credit and torrent announce strippingnpm run builddocker compose configpasses for prod, local and dev;caddy adaptpasses🤖 Generated with Claude Code