This document contains general security information for the application that system administrators should be aware of and consider when deploying this application in a production environment.
If you have identified any security issues or have other concerns, please report immediately to contact@bethibande.com
Frontend authentication is done via http-only, secure, same-site strict cookies. The current user session is stored as "Identity" and a refresh token, restricted to the refresh endpoint is stored as "RefreshToken". The sessions used for this are stateful and — by default — expire after one hour. Refresh tokens expire after 7 days.
Alternatively, the Authorization header may be used to authenticate users. This always uses access tokens generated by the user.
Currently, both basic and bearer authentication is supported.
Access tokens work both for the API itself and the repository/package-manager specific endpoints under /repositories/{package-manager}.
Access tokens implicitly grant access to all resources the owning user is permitted to access. This includes user information, resetting passwords (only possible by providing the current password) and full repository access (as much as the user is permitted to access, both read and write operations).
In the future we may support further restricting access token permissions.
By default, the application accepts all proxy headers (X-Forwarded-For, X-Forwarded-Proto, X-Forwarded-Host).
As such, you should always run the application behind a reverse-proxy that strips and overrides these headers.
Allowing users to forge these headers may allow them to bypass rate-limits.
Disabling the proxy headers is not recommended as doing so will break certain features and cause rate-limits to be applied incorrectly.
To prevent brute-force attacks and resource exhaustion, we enforce rate limits on sensitive endpoints. These limits are defined in the application.properties. Proxy-Headers (X-Forwarded-For) are used to track the originating IP address. Do NOT expose the API directly to the internet.
Note
Rate limits are currently tracked per-container. In distributed deployments without sticky sessions, effective limits may be higher. For such environments, we recommend implementing sticky sessions at the load balancer or using an external rate-limiting provider.
- Authentication: Login attempts are limited to 20 requests per hour, per IP address.
- Password Resets:
- IP Throttle: Password reset requests and token verification share a combined limit of 6 requests per 15 minutes or 15 requests per 24 hours per IP.
- User Quota: Each account is limited to 3 pending reset attempts per 24 hours. After this quota is reached, no further emails will be dispatched until the daily cleanup job runs.
- Security Note: To prevent account enumeration, the API returns an identical success message regardless of whether the email address exists in the database.
- Resource Protection (OCI Blobs): Downloading OCI blobs is limited to 100 requests per hour to prevent excessive egress network costs.
Caution
As of right now, distributed, multi-pod deployments are experimental and pose some security risks. Port 8081 (internal communication, only enabled if distributed mode is enabled) grants full, unauthenticated, access to the entire API. Ensure it is not accessible by pods not part of the deployment (using network policies) or disabled if not needed.
Distributed deployments in kubernetes with the necessary cluster permissions will expose an additional interface on port 8081.
This interface is used for internal pod-to-pod communication and must never be exposed to the internet or other untrusted clients/pods.
All requests to this interface will be implicitly authenticated as a system user, granting full, unrestricted access to the entire API.
Access to this port by other pods, not part of the deployment, must be blocked using appropriate network policies.
The default port 8080 may be fully exposed to the internet as it enforces user authentication.
If the management interface is enabled, a log message containing the host and port will be printed during startup.
You may also manually disable the distributed mode by setting repository.distributed to false.
This will, however, mean that you may only run one pod at a time. Running additional replicas can cause issues with job
scheduling, such as running jobs multiple times and possibly other features in the future.
User passwords are stored as bcrypt hashes in the database.
Access tokens and other secrets of external systems supplied to the application (such as S3 secrets), are currently stored in plain text and may even be retrieved through the API. In the future, we may switch to encrypting these secrets and only returning encrypted values using the API. But in the meantime, you have to ensure that your database is properly secured and that the management interface mentioned in Kubernetes deployment is secured, if enabled.
Should your database ever be compromised, you must immediately re-roll all external secrets.
User session tokens, refresh-tokens and access tokens are also stored in plain text. Should your database ever be compromised, you must also immediately drop all contents of the following tables:
delete from accesstoken;
delete from usersession;
delete from refreshtoken;Running these commands will log out all users immediately and remove all access tokens. You still need to re-roll your external secrets (S3, SMTP, ...) though.
Note
All repositories configured in the application may share the same S3 bucket. This can make management easier and restricts security incidents to only one bucket (as long as the access credentials are restricted to this bucket)
For information on how S3 secrets are stored and handled, look at the remote access tokens section. The minimum permissions required by the S3 user are the following:
- List objects
- Get objects
- Head objects
- Multipart upload and Multipart copy
- List parts (for multipart uploads)
- Upload & Copy objects
- Delete objects
- Ranged get operations must be supported