# Security policy This project is in development. No stable version or public security-support commitment has been issued. Do not interpret test results or dependency scans as proof that the application is free of vulnerabilities. ## Reporting Private vulnerability reporting is enabled on the public GitHub repository. Use [Report a vulnerability](https://github.com/marcvandecoevering/Dirflux/security/advisories/new), or the repository's Security tab. Do not include passwords, session cookies, installation codes, private links, personal filenames or live user data in public issues. A useful report includes the affected version, minimal reproduction with synthetic data, platform and filesystem, impact, and any proposed fix. There is no bug bounty or guaranteed response-time agreement. ## Update process The **Daily security maintenance** workflow scans the published `beta` image on AMD64 and ARM64, plus its source lockfile (including bundled browser dependencies), every day at 05:41 UTC. No fixable finding means no build. GitHub may delay scheduled runs. When fixes are available, it refreshes the pinned Node 24 base, upgrades Alpine packages and applies compatible npm updates. Direct npm dependencies never cross a major version automatically. Both images must pass a short startup/login/upload/download/share/restart check and a fresh scan: targeted findings must disappear and no new findings may be introduced. Existing findings without an available fix remain reported; they do not by themselves trigger a build. Only verified images are published to unique `security--` tags and the Unraid `beta` channel. Dependency changes are recorded on `main` with a matching source tag. Unreleased application changes, concurrent source/channel changes, missing scan data or failed checks stop promotion. Native archives and existing version tags are not replaced by container security maintenance. A failed candidate creates one issue; the same candidate is not built again until its dependency/base/package-index inputs or maintenance logic change. Human review is needed for major upgrades and application-code vulnerabilities. Maintenance uses standard public Linux runners, no paid runners or external services. Large temporary image artifacts are deleted after the run (one-day expiry if cleanup fails). Small plan/evidence artifacts expire after one day. Running Unraid containers still need an image update; this workflow does not access your server. 1. Triage reports and dependency advisories against actual use, including development/build dependencies that enter bundled browser assets. 2. Reproduce the defect and add a regression check when appropriate. 3. Update the application or dependencies and run the functional, native package and container checks. 4. Review the change and release notes; publish versioned source/packages/images from the reviewed revision. 5. Notify users through the release notes and Unraid update metadata. Document required configuration changes or mitigations. Dependabot is configured for weekly version-update pull requests. Dependabot update jobs are running on GitHub; vulnerability alerts, automated security-update pull requests and private reporting are enabled. Branch protection and the complete private reporting submission flow remain to be verified. Verification CI uses read-only permissions. The optional draft-release job receives contents-write permission; the optional image-publishing job receives packages-write permission. Update pull requests are not automatically merged or released. The manual release-candidate workflow resolves an existing version tag to an exact commit, runs the verification workflow on it, and creates a checksummed native candidate only after those jobs pass. Packaging verifies that the tag still points to the selected commit. An optional input creates a draft prerelease after verifying the downloaded candidate and remote tag again; it does not publish that draft. A separate opt-in image-publishing job promotes the exact verified AMD64/ARM64 artifacts to GHCR. Candidate metadata and SHA-256 checksums provide traceability and integrity checks, not a signature or a promise of security support. ## Deployment boundary Run a single application process as a non-root user with access only to its own files and configuration. Protect configuration and backup directories from other users. Shared links deliberately grant unauthenticated access to the linked content. Users share a common file tree rather than isolated home directories. Credential changes and the associated revocation of existing sessions commit in one SQLite transaction. Account deletion also removes that account's sessions and owned share links in one transaction. A failed statement rolls back those grouped changes; tests inject SQLite statement failures and verify that the prior account/access state survives. This is not a physical power-loss or storage-corruption test. An exclusive connection to `CONFIG_DIR/instance-lock.sqlite` prevents cooperating app instances from using the same configuration directory simultaneously. The lock is acquired before recovery can touch temporary files, and released on normal close, failed startup or process termination. Do not delete or replace the lock file to bypass a running instance. This depends on working SQLite filesystem locks and is not a distributed coordination mechanism; separate configuration directories do not coordinate writes to a shared file tree. Keep configuration on storage suitable for SQLite. The implementation uses [SQLite exclusive transaction locking](https://www.sqlite.org/lang_transaction.html). Use HTTPS for remote access and secure cookies. Review the README's resource limits and filesystem assumptions. The app does not provide host-level isolation against processes that can rewrite its underlying storage. It must not be deployed as a privileged container or with the Docker socket mounted. Authentication attempts are limited to 15 per 15-minute window per direct socket address. The in-memory tracker holds at most 1,000 active address windows; when full, new addresses are rejected rather than evicting active restrictions. HTTP 429 includes Retry-After. Expired windows free slots, and a successful login resets its address counter. Forwarded address headers are not trusted. Clients behind one reverse proxy therefore share its counter; configure per-client limits at the proxy as well. These limits do not provide complete denial-of-service protection. ## Container advisory checks Container CI runs digest-pinned Trivy 0.76.1 against an archive of each built image. Reports include known OS/package advisories and are retained as workflow artifacts. HIGH or CRITICAL findings block release promotion; lower-severity findings remain visible in the report. npm audit separately checks the dependency tree, including the browser build dependencies. Scanner databases and advisory coverage change over time; neither scan is a full application penetration test. The runtime container excludes npm/npx after installing production dependencies. They are build/install tools, not needed to run Dirflux. This removes their bundled dependency advisories from the shipped runtime instead of suppressing scan findings. Native installations should use a maintained Node.js release (minimum 24.22.1) and an updated npm installation. # Container initialization and initial credentials (beta.3) The Docker entrypoint starts as root to prepare empty `/files` and `/config` mount roots only. It never recursively changes ownership or permissions of existing data, rejects symbolic-link mount roots, and drops supplementary groups, GID and UID before starting the application. The Unraid template grants CHOWN, FOWNER, DAC_OVERRIDE, SETUID and SETGID to this initializer; the running application has zero effective capabilities. An explicit non-root container user bypasses initialization. `INITIAL_ADMIN_PASSWORD` and optional `INITIAL_ADMIN_NAME` bootstrap an administrator only if no account exists. A short password fails startup; the setting cannot reset existing credentials. Docker environment variables and Unraid templates are visible to host administrators even when a form masks the field. Remove the initial-password setting after setup if desired. Without it, the existing one-time setup-token protection remains active.