Skip to content

Security ​

Teldock handles bot credentials, user accounts, and file access. This page explains how those are protected, the authentication and rate-limiting behavior, and the steps a self-hoster should take to keep a deployment safe. For the deployment commands referenced here, see Deployment.

Security model ​

Teldock is self-hosted and single-tenant per instance. Each user connects their own Telegram bot and storage channel, so credentials and file content are isolated per account. The server stores only metadata; raw file bytes are streamed to and from Telegram on demand.

Protection mechanisms ​

MechanismWhat it protectsImplementation
Encrypted bot tokens at restTelegram bot tokens in the databaseAES-256-CBC with a per-record random IV; key derived from ENCRYPTION_KEY via scrypt
Password hashingUser account passwordsbcrypt with 12 salt rounds
Short-lived signed URLsDownload and preview accessFile-scoped JWTs (type: "file-access"), default lifetime FILE_ACCESS_TOKEN_EXPIRE = 5m
Internal Telegram IDs hiddenStorage location disclosureFile.toJSON() strips telegramChatId, telegramMessageId, telegramFileId; TelegramConfig.toJSON() strips the encrypted token and chat ID
Rate limitingBrute force and abuseGlobal 100 requests / 15 min; login 20 attempts / hour; WebDAV 5000 requests / 15 min with separate failed-auth protection
Input validationMalformed and hostile requestsZod schemas validated at the route boundary
Output and header hardeningXSS, clickjacking, MIME sniffingHelmet with a strict Content Security Policy
SQL injection preventionDatabase integritySequelize ORM with parameterized queries
Share access controlShared-link abuseOptional bcrypt password, expiration, and download limits
Secret validation at bootMisconfigurationassertSecrets() fails startup on missing or placeholder secrets

Authentication flow ​

Teldock uses short-lived JWT access tokens plus a longer-lived refresh token.

  1. Register / login returns an access token and a refresh token.
  2. The access token is sent as Authorization: Bearer <access-token> on protected routes.
  3. When it expires, the client calls POST /api/auth/refresh with the refresh token to obtain a new access token.
  4. File downloads and previews use a separate, short-lived signed URL.
TokenSecretDefault lifetimeEnvironment variable
Access tokenJWT_SECRET15 minutesJWT_EXPIRE
Refresh tokenREFRESH_TOKEN_SECRET7 daysREFRESH_TOKEN_EXPIRE
File access URLJWT_SECRET5 minutesFILE_ACCESS_TOKEN_EXPIRE

The access token payload includes the user ID and email. The file access token is bound to a single fileId and a stream disposition (attachment for download, inline for preview), so a leaked URL cannot be replayed against another file or used for the other disposition.

INFO

Login always performs a bcrypt comparison, even when the email does not exist, so response timing does not reveal whether an account is registered.

Rate limits ​

ScopeLimitWindowResponse on exceed
Global API (/api/)100 requests15 minutes429 with { success: false, error: "Too many requests, please try again later." }
Login (/api/auth/login)20 attempts1 hour429 with { success: false, error: "Too many login attempts, please try again after 1 hour." }
WebDAV (/webdav)5000 requests15 minutes429 with { success: false, error: "WebDAV requests are limited" }
WebDAV failed auth20 attempts15 minutes429 with { success: false, error: "Too many failed WebDAV authentication attempts" }

The limits are enforced in backend/src/app.js (global and login) and backend/src/routes/webdav.routes.js (WebDAV). WebDAV is driven by mounted clients that issue many requests per operation, so its general limit is generous and configurable through WEBDAV_RATE_LIMIT_MAX. Brute-force protection is applied separately to failed authentication attempts only (skipSuccessfulRequests), so legitimate mounted clients are never throttled.

Data privacy ​

  • No file bytes on disk. The server never persists uploaded content; it streams to Telegram and keeps only metadata in MySQL.
  • Per-user isolation. Every file, folder, tag, bot token, and Telegram configuration belongs to a single user, and queries are scoped by userId.
  • No third-party analytics. The application does not embed trackers or telemetry.
  • Open source. The full source is auditable; there are no hidden network calls beyond the Telegram Bot API.

Operational hardening checklist ​

For anyone self-hosting Teldock:

  • [ ] Rotate secrets. Generate unique values for JWT_SECRET, REFRESH_TOKEN_SECRET, and ENCRYPTION_KEY; never reuse the example placeholders.
  • [ ] Keep ENCRYPTION_KEY stable and secret. Back it up separately. Changing it makes encrypted credentials and encrypted file parts unreadable.
  • [ ] Restrict the database user. Grant the application user only the privileges it needs on the Teldock schema; do not run the API as root.
  • [ ] Run behind HTTPS. Access tokens and signed URLs travel in headers and query strings.
  • [ ] Set CORS_ORIGIN tightly. Point it at the exact public frontend origin.
  • [ ] Patch dependencies. Run npm audit regularly and apply updates.
  • [ ] Limit WebDAV exposure. WebDAV uses HTTP Basic auth; restrict it at the proxy if you do not need it publicly.
  • [ ] Back up the database. See Deployment.

Hardening log ​

The project's security changes are tracked in SECURITY_CHANGES.md at the repository root, which documents fixes for authentication bypass, bot-token exposure, memory-efficient streaming, stored XSS prevention, and rate limiting. Release-level summaries live in the Changelog.

DANGER

Teldock relies on the Telegram Bot API and your own Telegram account/channel. Telegram's Terms of Service apply, and Telegram may change limits or remove functionality at any time. Do not treat Teldock as reliable primary storage: keep independent backups of anything important and expect that availability depends on a third-party service outside your control.

Released under the MIT License.