Product

Overview

How it works Watch it work All 35 features Screenshots How ForgeRepo™ is secured

Keep bad packages out

Malware scanning Typosquat detection Dependency confusion protection Cooling off new releases Allow lists and block lists

When something goes wrong

Kill switch Who has it Lockdown and degraded modes Vulnerability monitoring

Developers and approvals

Requests and auto approve Check, walk and review Waivers Dry run
Formats

Languages

Private npm registry PyPI proxy and private index Private NuGet feed and proxy Maven repository proxy RubyGems mirror Composer and Packagist proxy

Apple, containers and Linux

CocoaPods CDN mirror Swift package registry Docker registry mirror RPM mirror for dnf and yum APT mirror for Debian and Ubuntu

Use it as

An npm firewall Artifacts, SBOMs and lifecycle More than one node SSO, roles and allow lists
Learn

Guides

Learn secure development Secure coding Secure pipelines Unsafe vs safe Security and development

Supply chain

Supply chain attacks, 2016 to 2026 Software supply chain security
Compare Side by side, all four ForgeRepo™ vs JFrog ForgeRepo™ vs Sonatype ForgeRepo™ vs Cloudsmith
Docs

Start

Getting started Download All documentation Questions

For developers

npm setup pip setup docker login Push a Docker image CI basics

For administrators

First setup Rules and their order Six incidents, walked through Backup and upgrade
Pricing Install it

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-For to 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.

packages.example.com/_admin/
Whitelists: the portal allow list, the client allow list, and break glass keys.

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.