Security

What it protects, and how

What modest-deploy protects against, how, and what it doesn't cover yet.

An early release. It has had internal adversarial review (by AI reviewers, each given one area), and is tested end to end on Ubuntu with systemd, but it hasn't been independently reviewed.

What it promises

  1. Only main's newest commit that passed CI is ever deployed.
  2. A message can't make the server run a command.
  3. Access to GitHub doesn't give access to the server.
  4. One product can't read or change another's code, data, or keys, or the server's.
  5. A bad deploy doesn't take a product down.

Each one is covered by the measures below, with tests, including an end-to-end test on Ubuntu with systemd.

How

AgainstWhat it does
A forged deploy messageEach product has its own secret; every message must carry a valid HMAC-SHA256 signature of its exact body, compared in constant time
A message for anything but a passed CI run on mainOnly a finished, successful run of the product's CI workflow, for a push to main, in its own repository, deploys
An old message sent againOnly main's newest commit is ever deployed, and a commit that failed isn't tried again by a message, only by hand
A message that names something to runThe listener runs nothing: it leaves a request holding a known product's name and a commit checked to be 40 hex characters
Someone in GitHub, the repository, or a workflowGitHub holds no key to the server, only the webhook secret, which no workflow can read
A server pretending to be GitHubGitHub's host keys are fetched from GitHub's API over HTTPS at install; nothing is trusted on first use
A product taking another portEach product can listen only on its own port (on Ubuntu 26.04 LTS, tested end to end)
A product reaching another, or the serverIts own user; a read-only system and code; private /tmp; no new privileges; other users' processes hidden; the server's keys out of reach; write access to its own data only
A package's install scriptDependencies installed exactly as the lockfile says, with install scripts off, by a separate user
A repository's own npm or git settingsIts .npmrc is removed before npm runs, and npm's and git's settings are pinned, so nothing it carries chooses what runs
A build reaching another productEach product has its own build user, which alone can read its deploy key and its copy of the repository
A build that ran code of its ownAll the build user's processes stopped after every step, before root touches its files; each deploy starts it clean; hard links refused
A commit filling the shared diskReleases over 1GB or 200,000 files refused, sizes counted before anything is written, and 1GB always kept free
A bad deployThe product is checked once started, and the version before comes back if it doesn't answer
An unsafe servercheck looks at SSH, automatic updates, and what's listening, and install and add refuse until it's fixed
A key committed to this public repositoryCI fails on IP addresses, private keys, and tokens

The threat model has every threat, its measure, and where in the code it lives.

What it doesn't do yet

  • The server is only as safe as its setup. modest-deploy checks the main points, but can't see everything, such as a provider's firewall.
  • Products trust their dependencies. Install scripts are off, but a compromised package still runs when the product does, inside its sandbox.
  • On Ubuntu 24.04 LTS, a product that's been broken into could listen on another port, to the outside or on another product's port while that one restarts. modest-deploy lets each product listen only on its own port, but that needs a systemd built with its BPF framework: Ubuntu 26.04 LTS's is, 24.04 LTS's isn't. On 24.04 LTS, the firewall blocks the outside, and check and the nightly run report it.
  • A fetch isn't limited in size, so someone who can push to a product's main could fill the disk as it's fetched. Deploys stop once less than 1GB is free.
  • The deploy service runs as root, to own releases and restart products. It runs git and npm as a separate user, and takes only a checked name and commit from a request.

How the project stays secure

  • No runtime dependencies, and CI fails if one is added, or if anything but Node's own modules is imported.
  • CI refuses invisible or direction-changing characters in code, and any address, key, or token committed.
  • CodeQL checks every change, OpenSSF Scorecard grades the project weekly, and GitHub Actions are pinned to exact commits.
  • An end-to-end test runs it on Ubuntu with systemd: install, launch, deploy, sandbox, rollback, and backups.

Reporting a vulnerability

Please don't describe it in public. Use the repository's Security tab, then Report a vulnerability, with what you found, how to make it happen, and what an attacker could do with it. You'll hear back within 5 working days.