Honest about what we protect against, what we don't, what's stored (nothing persistent), and how to report a vulnerability. No hand-waving. security is a property, not a feature.
Who might attack this bot, and what they'd be trying to accomplish. Spelled out so the security claims are grounded in specific scenarios.
xrpl, viem, or any direct dep is within our supply chain. Pinning + verification helps, doesn't eliminate.config.env in logs or a public repo leaks everything. Deploy guides tell you how to avoid this.Exhaustively. This is the full list of data the bot handles, where it lives, and how long.
| Data | Source | Lifetime | Persisted? |
|---|---|---|---|
| Owner addresses (XRPL, EVM, Solana) | User's config.env |
Process lifetime | No |
| Discord bot token | User's config.env |
Process lifetime | No |
| Telegram bot token | User's config.env |
Process lifetime | No |
| Twitch OAuth token + Client ID | User's config.env |
Process lifetime | No |
| X credentials (API key, secret, bearer, access token, access secret) | User's config.env |
Process lifetime | No |
| Announce channel IDs | User's config.env |
Process lifetime | No |
| Thank-you templates | User's thankyous.json |
Process lifetime | No |
| Incoming tip events (amount, tipper address, memo) | Chain RPC | Duration of processing (seconds) | No |
| Chat message text (EVM memo-pairing) | Chat platform event | 60 seconds | No |
| ENS name cache | Ethereum mainnet RPC | Process lifetime | No |
Component status (for /check) |
Internal | Process lifetime | No |
| HTTP access logs | Fastify (if log level set) | stdout only (host may capture) | No (by the bot) |
| Event logs (bot-level, structured) | pino | stdout only | No (by the bot) |
The bot writes nothing to disk beyond what Node.js writes itself (stdout, which the host may capture). Restart it and every row above resets.
Every direct dependency in package.json is pinned to a specific version audited clean at release time. When you npm install, you get exactly the versions that were tested and reviewed.
Transitive dependencies (dependencies of dependencies) resolve according to each direct dep's own pinning. This isn't fully deterministic — a direct dep could pull in a newer transitive later. npm audit catches most issues here.
npm audit reports 0 vulnerabilities at release timepostinstall, preinstall, or install scripts in any direct dep — the biggest supply-chain attack vectorCVEs emerge after release. A dependency audited clean today may have a vulnerability published tomorrow. The patch cadence section below explains how we handle that, but the honest reality is: no pinning policy prevents the existence of new CVEs. It only controls when you absorb them.
If you've deployed and more than 30 days have passed, run npm audit in your bot folder. If it reports issues, check the releases page — we may have already shipped a patch.
Exhaustively. Every outbound network call the bot makes in normal operation:
xrplcluster.com by default, configurable via XRPL_WS_URL. Subscribes to account transactions. Only active if XRPL is configured.EVM_BASE_RPC_URL. Subscribes to USDC Transfer logs. Only active if Base is configured.api.mainnet-beta.solana.com by default or your configured SOL_RPC_URL. Subscribes to account logs. Only active if Solana is configured.gateway.discord.gg. Bot login + receive-events. Only active if Discord is configured.discord.com. For posting announcements.api.telegram.org. Login + receive + post. Only active if Telegram is configured.eventsub.wss.twitch.tv. Subscribes to channel chat messages. Only active if Twitch is configured.api.twitch.tv. For creating EventSub subscriptions and posting chat messages. Also contacts id.twitch.tv for token validation when needed.api.x.com (sometimes via api.twitter.com). Polls for mentions, posts tweets and replies. Only active if X is configured.ENS_MAINNET_RPC_URL if set. For ENS reverse-resolution. Optional.You can verify this by running the bot behind a restrictive firewall that allows only the chain RPC and chat-platform endpoints. It should work identically.
DISCORD_BOT_TOKENTELEGRAM_BOT_TOKENhttps://mainnet.infura.io/v3/YOUR_KEY)Owner addresses are NOT secret — they're public by nature, published in the configurator and broadcast on-chain with every incoming tip.
src/logger.ts and src/config.ts — config is loaded, used, never printed./check page renders addresses (public) but not tokens (secret). The /tip page doesn't include tokens.config.example.env as a template. The actual config.env is the user's to create, and .gitignore excludes it from any git repo.config.env to git. The included .gitignore prevents this if you use the supplied file.fly secrets command — not via a file in the repo./revoke and re-issue. Twitch: regenerate the User Access Token via the Twitch CLI or a token generator. X: regenerate credentials in the X developer portal — note that regenerating the app-level API Key invalidates any access tokens derived from it, so you'll likely regenerate the Access Token and Access Token Secret too.Things we know about and have explicitly chosen not to address, with the reasoning. Don't report these as bugs — they're by design.
For EVM tips, the bot pairs a recent chat message with the incoming USDC transfer by looking up the freshest buffered message text. If a user types their message more than 60 seconds before sending the tip, the memo won't land.
Why we accept this: extending the window means storing more data longer, which we don't want. Users quickly learn to mention the bot right before tipping. In practice, 60 seconds is plenty.
The default Solana and Base/Arbitrum RPC endpoints are public and rate-limited. Under any real traffic, the bot will get throttled and miss events.
Why we accept this: sign-up for dedicated RPCs (Alchemy, Helius, QuickNode) is easy and has free tiers. Configuring them is a one-line change. We default to public RPCs so setup works without an account, but the deploy guides remind users to upgrade.
If the same transaction appears twice in chain RPC results (rare, but possible during reorgs or RPC glitches), the bot may announce it twice.
Why we accept this: deduplication would require persistent state (which we don't have). Double-announcements are a minor annoyance, not a security issue. We'd rather have the simpler, stateless design.
If a creator's XRPL account doesn't have trust lines for USDC or RLUSD, and ALLOWED_ASSETS includes those, tippers' transactions fail and they lose the fee. The bot can't prevent this — it's a chain-level constraint.
Mitigation: the wallet guide explains trust lines explicitly, and the bot's ALLOWED_ASSETS config lets creators restrict to assets they actually hold trust lines for.
Found a security issue? Thank you for looking. Here's how to report it responsibly:
Email: security@justthetips.dev (not yet configured — until it is, open the contact form via the site footer or reach out through the troubleshooter's contact path).
Please include:
0.1.0-alpha.7)Please don't publicly disclose until we've had a reasonable chance to patch. For most issues, 30 days is reasonable. For actively exploited issues, we'll ship a patch immediately.
npm audit — must be 0 vulnerabilitiesNew features. New chains. New platforms. Breaking config changes. As of 0.2.0-alpha.1 the bot is feature-complete relative to its original four-chain, four-platform scope; patches fix security and nothing else. If you want a fifth chain or a different platform, forks are explicitly welcome under BSL 1.1.
Patches appear on the releases page. There's no email list, no RSS, no push. If you've deployed, bookmark that page and check it periodically — every 30 days is a reasonable cadence, and running npm audit locally catches most issues between checks.