Repository navigation
Spam protection and API keys for creating pastes - #30
Merged
Merged
Conversation
95 % of all pastes came from one address that used the service as file storage (blocks of about 0.5 MB of base64, one year each), the rest was link and comment spam. The create route had only an in-memory limit per address, and that address came from CF-Connecting-IP or the first X-Forwarded-For entry, both set by the client. - The client address is X-Real-IP (set by Apache) or the last X-Forwarded-For entry, never a header the client chooses. - The form needs a solved Cloudflare Turnstile (required in production, fails closed), the same origin, an untouched honeypot and a signed form stamp at least two seconds old. Per address it may create 20 pastes and 5 MB a day, counted in the database. - Scripts need an API key. scripts/api-key.sh (help, list, create, revoke, delete) manages them on the server; only the SHA-256 is stored. - Both ways pass content checks: encoded files, link spam and the same content again within a day are turned down. - The privacy policy names Turnstile, the README the key requirement. - Vitest for the rules, and a build workflow that type-checks, tests and builds every pull request.
Dependency ReviewThe following issues were found:
License Issues.github/workflows/build.yml
OpenSSF ScorecardScorecard details
Scanned Files
|
This was referenced Oct 30, 2026
CodeQL flagged the SHA-256 of an API key as an insufficient password hash. Keys are 32 random bytes, but scrypt is the password-grade choice and keeps a leaked table useless even against a weaker key. Hashing now costs a few milliseconds, so it is bounded: a key without the exact format (mskp_ and 43 base64url characters) is turned down before hashing, and an address is stopped for ten minutes after ten wrong keys. The hash runs off the main thread.
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.
Why
The database is mostly spam. 95 % of all pastes come from one address that uses the service as file storage: blocks of about 0.5 MB of base64, kept for a year, 40 to 90 a day since September 22. The rest is SEO and comment spam built around links.
The only brake was an in-memory limit per address, and that address came from
CF-Connecting-IPor the firstX-Forwarded-Forentry. Both are set by the client, so a script could pick a new address per request. The site is not behind Cloudflare.What
Client address.
X-Real-IP(Apache sets it from the connection) or the lastX-Forwarded-Forentry, which Apache appends. Never a header the client chooses.The form, in order of cost:
Scripts need an API key (
Authorization: Bearer mskp_…). Without a key the API answers 401. Keys are managed on the server withscripts/api-key.sh(help,list,create,revoke,delete), only the SHA-256 is stored (migration003_api_keys.sql). A key skips the form checks and has its own limit of 120 per hour.Content checks for both ways: an unbroken run of 16 KB of base64/hex, or a large paste made almost only of wrapped base64, is an encoded file. Text that is mostly links, or forum markup with several links, is link spam. The same content again within 24 hours is a repeat.
Privacy policy (Turnstile, retention of the IP hash), README (API key, key commands) and
.env.exampleare updated. Vitest covers the rules, and a new build workflow type-checks, tests and builds every pull request.Before merging
The server's
/opt/msk-paste/.envneedsCAPTCHA_SITE_KEYandCAPTCHA_SECRET_KEYfrom a Turnstile widget forpaste.msk-scripts.de. Without them the form refuses to create pastes in production.Checked
revoke401list,create,revoke,delete,helpwork