dev docs · security

Security policy

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.

current

This policy applies to version 0.2.0-alpha.1, the April 2026 release that completed the originally-scoped four-platform surface (adding Twitch and X to the Discord + Telegram MVP from 0.1.0-alpha.7). Dependencies audited clean against published CVEs as of this date. Future patches announced on the releases page.

On this page

  1. Threat model
  2. What's protected, what isn't
  3. What data exists in the system
  4. Dependency policy
  5. Network boundaries
  6. Secret handling
  7. Known limitations
  8. Responsible disclosure
  9. Patch cadence

Threat model

Who might attack this bot, and what they'd be trying to accomplish. Spelled out so the security claims are grounded in specific scenarios.

Realistic attackers

What they could realistically want

What's explicitly out of scope

What's protected, what isn't

✓ Protected by design

  • Creator funds. Bot has no signing authority, no spending path, no way to initiate transfers.
  • Tipper funds. Tipper signs in their own wallet. Bot never sees private keys.
  • Tipper identity. Bot doesn't log user IDs, IP addresses, or usernames. Only message text, held 60 seconds.
  • Historical tips. Stored only on-chain (where they were anyway). No bot-side database to breach.
  • Against downtime loss. If the bot crashes, tips still land on-chain. Bot just misses the announcement.
  • Against most injection attacks. No SQL (no database), no HTML template evaluation (plain string substitution), input validation at chain watcher boundaries.

✗ Not protected against

  • Leaked bot tokens or credentials. If you post your Discord token, Telegram token, Twitch OAuth token, or any of the five X credentials publicly, anyone with them can impersonate your bot. Rotate immediately at the platform's developer portal.
  • RPC provider collusion. If your chain RPC provider returns false data, the bot trusts it. Use reputable providers.
  • Compromised dependencies. A malicious update to xrpl, viem, or any direct dep is within our supply chain. Pinning + verification helps, doesn't eliminate.
  • Misconfigured deployments. Exposing config.env in logs or a public repo leaks everything. Deploy guides tell you how to avoid this.
  • Chain-specific vulnerabilities. If a chain has a double-spend bug, the bot will announce the fake tip once the RPC reports it.
  • Phishing tippers away from the real bot via look-alike Discord accounts, Telegram handles, Twitch usernames, or X handles. Platform-level problem.

What data exists in the system

Exhaustively. This is the full list of data the bot handles, where it lives, and how long.

DataSourceLifetimePersisted?
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.

What's NOT collected

Dependency policy

Pinning

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.

Review criteria at release

Why this still isn't enough

CVEs 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.

Network boundaries

Exhaustively. Every outbound network call the bot makes in normal operation:

What the bot does NOT do over the network

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.

Secret handling

What counts as a secret

Owner addresses are NOT secret — they're public by nature, published in the configurator and broadcast on-chain with every incoming tip.

How the bot handles them

How you should handle them

Known limitations

Things we know about and have explicitly chosen not to address, with the reasoning. Don't report these as bugs — they're by design.

The 60-second message buffer window

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.

Public RPC rate limits

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.

No replay protection on announcements

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.

XRPL trust-line sensitivity

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.

Responsible disclosure

~ we take reports seriously ~

Found a security issue? Thank you for looking. Here's how to report it responsibly:

What to report

  • Anything in the codebase that could put a user's funds at risk
  • Anything that leaks secrets (bot tokens, API keys)
  • Supply chain concerns about dependencies we're pulling
  • Configuration patterns that could mislead users into dangerous setups
  • Architectural issues with the non-custody story

How to report

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:

  • A description of the issue and how to reproduce it
  • Affected version (e.g. 0.1.0-alpha.7)
  • If relevant, proof-of-concept code or steps
  • Your preferred name for credit (or "anonymous")

What to expect

  • Acknowledgment within 72 hours that we received your report
  • A real assessment within 7 days — either a triage, a fix in progress, or an explanation of why we consider it out of scope
  • Credit on the release notes when a fix ships, unless you prefer anonymity
  • No legal action for good-faith security research. We don't bug-bounty at this stage (we're not funded for it), but we're grateful for every responsible report

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.

Patch cadence

What triggers a patch

What a patch looks like

  1. Bump the affected dependency (or fix the code)
  2. Re-run the three-gate (typecheck + lint + tests)
  3. Re-run npm audit — must be 0 vulnerabilities
  4. Manually review the diff of the dependency bump for unexpected changes
  5. Cut a new tarball with a bumped version number
  6. Compute SHA-256, update the releases page
  7. Publish

What doesn't ship in a patch

New 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.

Announcement

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.

Related