English
Security
Rust-Srec handles access tokens, platform cookies, notification credentials, recordings, and chat data. Treat the host and every backup as sensitive infrastructure.
Authentication Boundary
- Change
admin/admin123!immediately. The application enforces a password change for the initial account, but the default credential must still never be exposed to a network. - Generate unique, random
JWT_SECRETandSESSION_SECRETvalues of at least 32 characters. RotatingJWT_SECRETinvalidates access tokens; plan the change as an outage for API clients. - Access tokens are short-lived. Refresh tokens are rotating session credentials and must be protected like passwords.
AUTH_DISABLED=trueis only a local development escape hatch. The backend accepts it only with a loopback bind address; do not build production procedures around it. In that mode requests are refused unless theirOriginis in theAPI_CORS_ORIGINSallowlist (or matches the request's ownHost), and unless theHostis a loopback name or the configured bind address — the latter is what stops a DNS-rebinding page from reaching the unauthenticated API. Widen the allowlist only for origins you control.- Repeated failed logins are throttled per account (5 failures per 15 minutes by default) and, much more loosely, per source address; a throttled attempt is answered with
429and aRetry-Afterdelay instead of another password hash. The source address is the TCP peer andX-Forwarded-Foris not trusted, so behind the bundled frontend or any reverse proxy every login is attributed to the proxy — do not rely on the per-address budget to isolate clients. See Configuration. - Tokens carry role names and exports include user accounts, but the route layer does not enforce a per-role authorization policy, and there is no identity-provider integration. See Scope and Limits.
Login attempts for unknown users perform the same bounded Argon2 verification work as current-format passwords. Unknown users and incorrect passwords return the same credential error; disabled-account status is returned only after the correct password is supplied. Throttled requests still avoid password work.
Full Backend Access Is Administrative Access
An authenticated login session or a full-access API key grants administrative authority over the backend's processes and files. Grant either only to people and integrations trusted to act as the operating-system account running the backend. Token role names do not restrict this authority; there is no separate operator role for managing recordings without executable configuration access.
This authority includes direct execution through an execute pipeline step and request-supplied BaiduPCS executable paths. It also includes indirect execution: engine and processor settings can select tool binaries, presets can contain command steps, and configuration imports can introduce these settings for later recordings or jobs. File paths, upload destinations, and move/delete steps can read, transfer, replace or remove data accessible to the service account. A configuration import or preset from another source therefore needs the same review as code that will run on that account.
Read-only API keys have a restricted endpoint/tool allowlist; use them when an integration only needs the supported read operations. They do not provide a recording-operator role. See API keys and MCP. Operating system permissions, service sandboxing, and container mounts limit the backend's reach: run it with only the filesystem, network and device access it needs. Full backend access does not itself grant privileges beyond that environment.
Revocable Login Sessions
Access tokens and rotating refresh tokens belong to a durable login session. Logging out revokes that session, including its already issued access tokens, while leaving other devices signed in. Logout-all revokes every login session and refresh token for the user. A password change revokes existing sessions in the same database transaction and requires a new login. Disabling an account also revokes its sessions; re-enabling it does not restore old tokens. Successful configuration imports revoke all login sessions and refresh tokens.
Session authorization checks durable revocation and current user state on every request that could grant access; a database failure cannot fall back to a cached grant. These actions do not revoke separately managed API keys.
After upgrading to session-bound access tokens, previously issued unbound JWTs can no longer authenticate. An existing valid refresh token can be exchanged for a bound token pair; otherwise sign in again. Clients must handle this one-time refresh or sign-in boundary even when an old access token has not yet expired.
Refresh Token Rotation
Clients must serialize refresh requests and save the replacement token before refreshing again. Each refresh token can issue only one replacement. Consumption and replacement storage commit together; a database failure rolls both back.
REVOKE_ALL_ON_REFRESH_TOKEN_REUSE defaults to true. Replaying a consumed refresh token from an open session revokes all of the user's login sessions and refresh tokens atomically, including already issued access tokens. Set it to false to reject the replay without revoking other sessions. Replaying a token from a session already closed by logout does not sign out other devices.
REFRESH_TOKEN_REUSE_GRACE_SECS defaults to 0. A positive value suppresses revocation of other sessions for replays within that many seconds of the original revocation, but the replay still fails and never issues another token pair. Unlike earlier versions, grace does not permit refreshing with a revoked token. A request that loses the atomic rotation race follows the same reuse policy, so with default settings it also revokes the winner's access and refresh tokens. Clients must serialize refreshes, including across tabs or server instances.
Download and log WebSockets revalidate their issuing session or API key every five seconds, with a three-second deadline for each check. Revocation, expiry, account restrictions, insufficient access, or a failed check closes the connection even if it is blocked sending data. Log archive download grants are single-use, last five minutes, and revalidate their issuing identity when consumed.
Network and Session Security
Terminate TLS before the frontend, set COOKIE_SECURE=true only if the proxy does not send X-Forwarded-Proto: https, and restrict both host ports with a firewall. Keep the backend private unless direct API consumers need it. Do not expose Swagger, media proxy routes, or logs to anonymous Internet clients.
The bundled frontend container runs its application server under an unprivileged account (nginx still starts as root to bind port 80 and hands request handling to unprivileged workers) and answers every request, error responses included, with X-Content-Type-Options: nosniff and Referrer-Policy: strict-origin-when-cross-origin. If the reverse proxy in front of it also sends them, set them in one place only. The container does not restrict framing, so dashboards can embed the web interface; to forbid that, add X-Frame-Options or a CSP frame-ancestors directive at your reverse proxy.
The stream proxy blocks private-network targets by default. Enabling stream_proxy_allow_private_targets allows authenticated users to make the service fetch internal addresses; enable it only for an explicit LAN-camera or restream use case.
Web and desktop playback relays use the source's proxy setting. The backend validates each media target and redirect before fetching it. Without a proxy, direct connections also check the addresses used by the connector. A saved proxy or the system proxy is a trusted egress endpoint for everything sent through it, from live checks and account sign-in to downloads and playback: it sees the platform traffic, can be on a private network, and controls remote DNS and routing. Use only proxies you trust with your accounts, and restrict access to internal destinations on the proxy too; the backend cannot verify a different DNS answer on the proxy's network. Proxy logins stay on the backend. Web playlist links use the browser session rather than embedding the backend access token.
Stream proxy and URL parsing share a global configuration snapshot for up to five seconds. Application writes and committed imports invalidate it immediately. Out-of-band database edits can take five seconds to become visible; expired snapshots are not reused if refresh fails. Administrative reads remain fresh.
Credential Refresh Storage
Cookies, tokens and logins are stored only in account profiles. A refresh saves the new cookies and any returned tokens to the profile together; a failure leaves the previous credentials intact, and tokens the provider did not return keep their existing values. A refresh or login that finishes after the account was edited, disabled, replaced or deleted is discarded instead of overwriting it. Configuration writes that include account fields are rejected rather than stored.
Secrets and Files
- Restrict
.env,DATA_DIR,CONFIG_DIR,LOG_DIR, configuration exports, and backup media. - On a systemd host the backend's secrets are in
/etc/rust-srec/rust-srec.env, mode0640ownedroot:rust-srec:JWT_SECRET, the VAPID keys, and any tool-path override. Every assignment in it overrides the unit's ownEnvironment=lines, so treat an edit there as a change to the service's configuration, not just to its secrets. UMask=0027in the shipped unit writes recordings-rw-r-----. They stay readable to therust-srecgroup, so adding an account to that group grants it read access to every recording and to the state directory. Grant that deliberately rather than loweringUMask=.- Saved proxies keep their usernames and passwords in plain text in the database and in configuration exports. The API and web interface show a proxy's username but never return its password.
- Account profiles (cookies, tokens and logins) and room passwords are present in configuration exports. Notification channels can contain SMTP passwords, bot tokens, webhook secrets, and custom headers.
- The Baidu Netdisk login session lives in BaiduPCS-Go's config directory (
BAIDUPCS_GO_CONFIG_DIR,/app/config/BaiduPCS-Goin Docker) — protect and back it up like a cookie store. With Remember for automatic re-login enabled, the login material is additionally stored plaintext in the application database (tool_credentials), like platform cookies; logging out deletes it. Manual and automatic logins send credentials through stdin, never child arguments or environment variables. A private temporary config directory blocks CLI history and imports only the successful account into the original config; other accounts, settings and history remain intact. Temporary directories use owner-only permissions (0700 on Unix, a protected owner-only ACL on Windows) and are removed after child cleanup. An unconfirmed cleanup retains the private directory and keeps account operations locked until the backend restarts. Privileged host access and the configured executable remain trusted. - Redact tokens, private URLs, usernames, cookies, and filesystem paths before sharing logs or screenshots.
- Run containers without unnecessary host mounts or device access. Add GPU devices only when the selected pipeline requires them.
- Review any
execute, upload, move, or delete-source pipeline step as code with filesystem and network access.
The shipped systemd unit already runs the service unprivileged under ProtectSystem=strict, NoNewPrivileges=yes, an empty CapabilityBoundingSet=, and SystemCallFilter=@system-service, so the process sees the system read-only apart from its state, log, and ReadWritePaths= directories. Keep those in place and add write access one path at a time.
PrivateDevices=yes hides /dev/dri and /dev/nvidia*: the System Health page shows no GPU section and ffmpeg falls back to software encoding. Hardware transcoding requires a drop-in setting PrivateDevices=no plus a DeviceAllow= entry for the render node; treat that as a deliberate relaxation of the sandbox.
Full API credentials can select tool executables and config paths. Treat that access as permission to run programs with the backend's operating-system identity; it is not a restricted operator role. Only configure trusted BaiduPCS-Go binaries.
Vulnerability Handling
Do not report suspected vulnerabilities in a public issue. Use GitHub private vulnerability reporting and include the affected version, impact, and a minimal reproduction with secrets removed. Security fixes are applied to main and included in a subsequent release.
For operational evidence and limitations, also read Data Governance and Support and Versions.