This is an English translation of the Indonesian original (SECURITY.id.md). If the two differ in interpretation, the Indonesian text prevails.
WorshipDeck stores the names and photos of people who are not its direct users, namely the personal data of members and of those serving. The server accepts file uploads, including PowerPoint files that are unpacked on the server. The server fetches images from web addresses that account holders supply, and by default it accepts any public host. On a server installation, WorshipDeck can be opened from other computers and phones on your network. These properties deserve scrutiny. See "Two Facts Most People Want Up Front" below, docs/threat-model.md for the full analysis of components and attack paths, and the Privacy Policy for what is stored and where.
In this document, "you" means the church or organization that installs and runs WorshipDeck, and "server" means the computer WorshipDeck runs on.
Two Facts Most People Want Up Front
- Does WorshipDeck send member data anywhere? No request in the code sends names, photos, or service content to a third party or to Wira Delta Indonesia. The server makes exactly two kinds of outbound request, and both only fetch an image from a web address an account holder chose: uploading an image from a web address (
postUploadFromURL), and placing an image from a web address into a PowerPoint file while that file is built. There is no request to Google Fonts, no update check, no telemetry, and no crash reporting. Service data leaves the server only through PowerPoint files and pages that account holders open, and through the experimental Data Sync, to an address an admin types in. - What network input does it accept, and how is it restricted? Without a valid session, the server accepts only the sign-in page, sign-in and sign-out requests, static files under
/assetsand/branding, the initial administrator setup request (restricted strictly to desktop mode, loopback connections from the local machine, and only while zero accounts exist), and the webhook endpoint. The webhook endpoint is not offered in this release and is disabled in the code until the feature is ready. Every other endpoint requires a session signed withAUTH_SECRETand checked again against the database on every request. The session travels in a cookie; the sync endpoints also accept the same signed session as anAuthorization: Bearerheader, so an admin signed in to one instance can sync with another. Admin paths, including PowerPoint import, font upload, factory reset, and Data Sync, also require the admin role. Fetching an image from a web address does not follow redirects, refuses loopback, private network, link-local, and cloud metadata addresses, and accepts only hosts inIMAGE_URL_ALLOWLISTwhen that list is filled in.
Reporting a Vulnerability
Please do not open a public issue for a security problem.
Report it privately through GitHub Security Advisories on the WorshipDeck repository. WorshipDeck's source code is public, so an outside reporter can reach this path, and the report stays private until a fix exists. Questions that are not about security can go to support@wiradelta.com.
You will get an acknowledgement, then a fix or an explanation of why the report is not a vulnerability. There is no bug bounty program and no guaranteed response time. This is a small project, and honesty about that is more useful than a promise it cannot keep. Only the latest release receives fixes. There is no long-term support branch.
Scope
In scope, and especially welcome:
- sign-in, sessions, and session revocation;
- the separation between the admin and operator roles;
- fetching images from a web address, including ways around the private address refusal;
- file uploads and PowerPoint file import;
- phone remote pairing and remote commands;
- Data Sync, even though it is still experimental, and any way to make the disabled webhook endpoint accept a request;
- text from an order of service or other data that appears as HTML on the congregation screen instead of as text.
Out of scope, with the reason:
- An attacker who already holds an admin account. An admin may change all content, upload files, and run sync by design; using that right is not a vulnerability.
- An attacker who can already read the server's file system or runs under the same account as the server. That person can read
data.db,.env, and theAUTH_SECRETin the data folder directly, so there is nothing the application could protect from them. - A server installation without HTTPS, with an
AUTH_SECRETthat is shared or copied from the.env.examplesample, or withNODE_ENVset to anything other thanproductionbehind HTTPS. These requirements are listed under "Deployment Requirements"; an installation that skips them is insecure regardless of the code. - The risks under "Known Risks" below. They are documented rather than fixed. Reports of a new way to exploit them are still welcome.
Projection Display and Injected Content
Orders of service, names, and service text reach the congregation screen as data, not as markup. The frontend code has no dangerouslySetInnerHTML and no direct innerHTML assignment anywhere in src/ and spa/src/, so React's default JSX rendering escapes text before it appears on the screen the congregation sees. A report that shows a path where text from an account holder appears as HTML is a valid, in-scope finding.
Deployment Requirements
The code does not enforce the requirements below. It only assumes they are met, and an installation that skips them is insecure regardless of the code.
- HTTPS for server installations, also on the church network. Run a WorshipDeck server installation behind an HTTPS reverse proxy (for example Caddy, Nginx, or Cloudflare Tunnel), also when the server is opened only from the church network. Without HTTPS, passwords and session cookies can be read by anyone on the same network, including guest Wi-Fi. The Windows installer is exempt from this requirement: it listens only on
127.0.0.1, so its traffic does not leave that computer. - A unique secret. Set
AUTH_SECRETto a random value of at least 16 characters, unique to each installation, and never commit it.npm run setupgenerates it at random. The Windows installer generates it by itself the first time it runs and stores it in the%LOCALAPPDATA%\WorshipDeck\folder; the first admin account is created on the setup screen. IfAUTH_SECRETis empty or shorter than 16 characters, nobody can sign in. NODE_ENV=productionbehind HTTPS. The session cookie gets theSecureflag only whenNODE_ENVisproduction. Without it, the browser will send the session cookie over plain HTTP.- Limit image sources. Put the image hosts you use in
IMAGE_URL_ALLOWLIST. Without that list, the server will fetch images from any public host. - Listen only where needed. The server listens only on
127.0.0.1unlessLISTEN_HOSTor--hostis set. Set it only when other computers or phones really need to open it, and only behind HTTPS. - Storage under your control. Keep the database and the upload folder on storage you control, limit who can sign in to the server, and make backups regularly.
Known Risks
The risks below are documented rather than fixed. The full description is in docs/threat-model.md.
- IP address for sign-in rate limiting. The sign-in rate limiter reads the client address from the
CF-Connecting-IPorX-Forwarded-Forheader when present. If the server can be reached without passing through a proxy that overwrites those headers, a client can choose its own address and avoid the per-IP limit. Put the server behind a proxy that overwrites those headers, and do not expose the server port directly. - Data Sync.
POST /api/sync/assets/checkdoes not limit the size of the request body;POST /api/sync/pushandPOST /api/sync/assets/uploadstop at 50 MB. The sync endpoints have no rate limit of their own (only signing in is rate limited), and sync transfers are not logged. A request from another origin is accepted only from origins listed inSYNC_ALLOWED_ORIGINS; when it is empty, onlylocalhostorigins are accepted.*accepts any origin, so do not use it on a server that can be reached from the internet. A signed session used for sync stays valid for up to 7 days, like the sign-in cookie, unless it is revoked. - Image sources open by default. See requirement 4.
Deletion Is Permanent
WorshipDeck has no trash. Data deleted through the application is gone from the database and cannot be recovered from the application. Deleting an announcement slide or a Background Library image does not remove the image file from the upload folder. A factory reset, which only an admin can run after typing factory reset, deletes all service content and upload files except fonts, and also cannot be undone. The details are in the Privacy Policy, under "Deletion".
Release Integrity
Building from source is always available: clone the repository at the commit or tag you choose, build it yourself, and you are running exactly the code you can read.
A Windows installer is published on GitHub Releases for each tag, named WorshipDeck-<version>-x64-setup.exe. The installer is still experimental; the main way to use WorshipDeck is a server installation. The installer is built by CI (.github/workflows/release.yml) directly from that tag's source code. The workflow runs the Go tests, the type check, and the guard tests before building the installer, and refuses to release if the tag, the version in package.json, and the matching section of CHANGELOG.md disagree.
The installer is not code-signed. Because of that, Windows SmartScreen will likely warn the first time it runs. That warning is normal for an unsigned installer, and for the same reason the warning cannot help you tell a genuine installer from a fake one.
What you can check is the SHA-256 checksum. Every release publishes a SHA256SUMS file next to the installer. Hash the file you downloaded and compare before running it. Know its limit: a checksum served from the same place as the download proves the file arrived intact, not where it came from. Code signing is the real fix, and it has not been done yet.
Privacy
If this repository ever contains data about a real person who did not consent to it, that is a security issue and will be treated as one. See .constitution/project/private-data.md.
Language
This is an English translation of the Indonesian original. If the two differ in interpretation, the Indonesian text prevails.