OpenProcessor's API (port 4603 by default) has no authentication, authorization, or rate limiting of any kind. It is designed to run on a trusted internal network behind your own reverse proxy / auth layer, not to be reachable directly from the internet.
This matters because several routes are genuinely dangerous without access control:
DELETE /query/image/{id}— deletes indexed data with no confirmation.DELETE /curation/projects/{project}/models/{model_name}— unloads and removes a promoted model from Triton.DELETE /curation/projects/{project}— deletes a project's indexes and directories. A real delete needs only?confirm=<slug>.POST /ingest/directory— performs an arbitrary server-side filesystem path read; anyone who can reach this endpoint can make the server read any path it has filesystem access to.POST /curation/projects/{project}/ingest/batchandPOST /curation/projects/{project}/datasets/preview— read server-side paths too, limited to the configured source roots (OP_SOURCE_ROOT_HOSTmount and the upload root).
The curation subsystem (see docs/CURATION.md, opt-in
behind the curation compose profile) adds about 237 operations, about 125 of
them writes, all under the same no-authentication model. Projects isolate data
from each other inside the application (an OpenSearch request guard refuses
cross-project access), but that is a correctness boundary, not an access
control: any caller can address any project.
If you deploy this service, put it behind a reverse proxy that enforces authentication, and do not map its ports directly to a public interface.
Cropwright is reachable on your LAN by default, for homelab or
small-business use. The API itself stays bound to 127.0.0.1. There is no login
on Cropwright — a warning is shown. Pass --local-only to opt out and keep
everything on 127.0.0.1.
setup-openprocessor.sh targets one computer and its local network
(homelab, small office). With the cropwright tier, the Cropwright web UI
is published on all interfaces (CROPWRIGHT_BIND_ADDRESS=0.0.0.0) so other
computers on the LAN can open it; its nginx proxies to the API over the
Docker network. Every backend port (API, Triton, OpenSearch, ...) stays
bound to 127.0.0.1 unless you pass --bind and confirm it. A specific
--bind address (say 10.0.0.5) also narrows Cropwright to that one
interface; --local-only always keeps it on 127.0.0.1.
The UI has no login, and it can reach every API route above. Use it only
on a network you trust, never port-forward it to the public internet, and put
a reverse proxy with authentication in front for anything wider. Install with
--local-only (or answer "no" to the LAN question) to keep it on this
computer.
The installer checks every downloaded file against the release's
SHA256SUMS, pins images (Cropwright's included) by digest from images.lock, and cross-checks each images.lock entry's
image repo against scripts/lib/image_keys.sh. These catch truncated or
corrupted downloads and an internally inconsistent release. They do not
prove who published the release: SHA256SUMS comes from the same origin as
the files it covers. Release signing is follow-up work.
- Grafana ships with the default credentials
admin/admin(GF_SECURITY_ADMIN_USER/GF_SECURITY_ADMIN_PASSWORDindocker-compose.yml). Change these before exposing Grafana to anyone but yourself. In gateway mode (OP_GATEWAY_SUBPATHS=true) Grafana refuses to start with the default or an empty password. The variable only sets the password when thegrafana_datavolume is first created; on an existing volume change it withdocker compose exec grafana grafana cli admin reset-admin-password <new>. - Prometheus and MLflow have no authentication at all. In gateway mode (see the monitoring guide) anyone who can reach the gateway port can read Prometheus and read and write MLflow experiments and registered models, exactly as they can already use the API. The gateway moves these from "one port each" to "behind the one gateway port"; it adds no login. Publish the gateway only on a trusted network or behind an authenticating reverse proxy. Gateway mode also refuses to start the four UIs when they are published beyond loopback.
- OpenSearch ships with its security plugin disabled by default
(
DISABLE_SECURITY_PLUGIN=true/DISABLE_SECURITY_DASHBOARDS_PLUGIN=trueindocker-compose.yml, commented "Disable security for dev (enable in production)"). There is no authentication on the OpenSearch or OpenSearch Dashboards ports either. Enable OpenSearch's security plugin before any production or multi-tenant deployment.
Any caller can register a VLM endpoint URL (there is no authentication) and
make the API send requests to it (a test call, a probe, and every labeling
call once it is activated). Endpoint URLs are therefore checked before use:
this stack's own services, link-local and cloud-metadata addresses, and
anything that resolves to them are refused for every spelling of the
address, redirects are never followed, keys are only ever
references to files on the host, and an endpoint outside this deployment
needs an explicit acknowledgement (OP_VLM_EXTERNAL_POLICY=deny refuses
them).
The residual risk is deliberate: a URL that resolves to another host on
your private network (a router, a NAS, an internal admin page) is a valid
VLM endpoint as far as the API can tell, so a caller who can reach the API
can make it send synthetic probe requests and OpenAI-shaped chat requests
there. DNS is checked when an endpoint is saved, tested, activated and
built, and again by every labeler before it sends, at most every 30 seconds
(a refusal is immediate and stays until the host is acceptable again). So a
name that changes its answer is caught within about 30 seconds, but a
request already sent, or sent inside that window, goes to whatever the name
resolved to then; the connection itself is not pinned to the checked
address. The probe of an endpoint outside the deployment is only made once
the endpoint carries allow_external, because the probe sends its key. A
credential written into OP_VLM_URL is dropped, never served or logged.
Put the API behind your own network controls, as the rest of this document
already says.
None of this is a bug to be reported — it's the current, deliberate state of the project, tracked internally as follow-up work. Authentication is explicitly out of scope for this release: this is a local tool meant to run on a trusted machine or private network behind your own reverse proxy / auth layer, not to be exposed to a network you don't trust.
If you find a security issue that is not one of the known gaps above (for example, a bug that lets an authenticated, intended caller escalate privileges, corrupt data outside their own request, or execute arbitrary code), please report it privately rather than opening a public issue:
- Preferred: use GitHub's private vulnerability reporting for this repository.
- Alternative: open a GitHub Security Advisory draft, or contact the maintainer via the email listed on the maintainer's GitHub profile.
Please include reproduction steps, the affected version/commit, and your assessment of impact. We aim to acknowledge reports within a few business days. There is no bug-bounty program at this time.
This project does not yet maintain parallel supported release branches.
Security fixes land on main; use the latest tagged release.