Security
The thing guarding the door has to be locked too
Every build in the company trusts a registry. That makes it a target, so ForgeRepo™ was written against the OWASP Top 10 from the first line, with authorization decided on the server for every request and every object. This page says how, specifically, so you can check.
Authorization on the server, per object
Five roles, checked by the API on every request. The portal hiding a button is tidiness, not the control. Requests, tokens and waivers are checked against their owner on every read and write, so one user cannot reach another's by changing an id. Settings, allow lists, keys and the upstream registries are admin only to read as well as to write.
Nothing secret is stored in the clear
Passwords are bcrypt hashes. Registry tokens and break glass keys are stored as SHA-256 and shown once. Upstream tokens, SMTP passwords, webhook secrets and bucket keys are write only: the page shows whether one is set and never the value, and none of them is ever exported or written to the audit trail.
Two network allow lists
One for the portal, one for the registry, because the machines that run installs are rarely the
ones you administer from. A portal request from anywhere else gets a flat 404: no login page, no
clue there is an admin side. The portal will not switch its filter on until your own address is on the list.
A way back in that is not a back door
Break glass keys are UUIDs made ahead of time, rate limited to five tries per address per fifteen
minutes, and a bad key gets the same 404 as no key, so nobody can hunt for live ones. nginx logs them as
[redacted]. enable_local_login.sh on the server restores password sign in through the
app's own code, into the audit trail.
Outbound calls cannot be turned inward
Webhook and SIEM addresses on the box itself, or on cloud metadata addresses, are refused, checked again on every send, and redirects are never followed. A PyPI file hosted anywhere but the registry itself must be on a public address, so an index page cannot send the box into your internal network.
Uploads are treated as hostile
Reviewed files are parsed in memory and never written to disk. A CycloneDX XML file that declares a DOCTYPE or entities is refused unread. Branding images are identified from their own bytes, and SVG is refused because it can carry script. Published tarballs must match their manifest's integrity.
Strict headers
The portal's Content-Security-Policy allows scripts and styles from itself only, no inline script,
and frame-ancestors 'none'. Add X-Frame-Options: DENY, no-referrer, same origin
opener and resource policies, HSTS behind TLS, and uploaded branding images served with
default-src 'none'; sandbox.
Impersonation that cannot become a takeover
An admin can act as a user for support, never as another admin, for 30 minutes at most, with a red
bar on every page. Everything is recorded as admin as jsmith, changing that user's password is refused,
and a copied impersonation cookie can never be turned into admin access.
Deploy it safely
- Keep the container port on
127.0.0.1, which is the default, so only the proxy can reach it. - Set
X-Forwarded-Forto the client address in the proxy. Never append to it, or a client can claim an allowed address. - Turn on Require tokens once pipelines have them, so every download is tied to someone.
- Put the portal behind its allow list, and keep one break glass key offline.
- Keep a local admin account with a password, even with single sign on, for the day the provider is down.
- Switch on Only answer package managers if the registry faces the internet, so scanners get a 404.
Scanners pointed at a registry often report exposed config.json or phpmyadmin. Those are
real npm packages, proxied. The docs explain how to tell, and how to make it stop.
Reporting a vulnerability
Please report security problems privately to the author through the
project repository rather than in a public issue, with enough to reproduce it. Fixes land
on master and setup.sh --upgrade picks them up.
One container, about two minutes
A Linux box with Docker, or one without it, and a reverse proxy for TLS. The installer does the rest and it is safe to run twice. Free, MIT licensed, nothing to sign up for.