Skip to content

Security: enforce authentication on the bundled NATS event bus#12317

Open
thistehneisen wants to merge 1 commit into
owncloud:masterfrom
thistehneisen:security/nats-event-bus-auth
Open

Security: enforce authentication on the bundled NATS event bus#12317
thistehneisen wants to merge 1 commit into
owncloud:masterfrom
thistehneisen:security/nats-event-bus-auth

Conversation

@thistehneisen
Copy link
Copy Markdown

Security: enforce authentication on the bundled NATS event bus

Summary

The bundled NATS server is started with no authentication. The internal
event bus carries security-relevant control messages (postprocessing /
antivirus verdicts, upload finalize/abort/revert, share and notification
events). Any party that can open a TCP connection to the NATS port can both
subscribe to and publish forged events of any type, because:

  1. The embedded NATS server is constructed without any
    username/password/token/NKey/authorization option — it accepts any client.
  2. oCIS already exposes OCIS_EVENTS_AUTH_USERNAME / OCIS_EVENTS_AUTH_PASSWORD
    for clients, but the server never enforces them (no accounts are
    configured server-side), so the client-side auth is currently inert.
  3. TLS (incl. mutual client-cert) is off by default, and the shipped
    multi-service example deployments bind the broker to 0.0.0.0.

Consumers trust event content with no message authenticity (single subject,
type is a plaintext metadata string). A forged PostprocessingFinished
(Outcome: continue / delete) or RevertRevision / CleanUpload event is
acted on by the storage layer with only a non-secret mount-id check, enabling
antivirus bypass, finalize-of-unscanned-content, and tampering/destruction of
other users' in-flight uploads; forged SendSSE / ShareCreated events enable
notification spoofing.

Affected code

  • services/nats/pkg/command/server.gonats.NewNATSServer(...) is called
    with only Host, Port, ClusterID, StoreDir, TLSConfig,
    AllowNonTLS. No authentication option is ever set.
  • services/nats/pkg/server/nats/options.go,
    services/nats/pkg/server/nats/nats.go — no
    username/password/token/NKey/authorization option exists on the embedded
    server wrapper.
  • services/nats/pkg/config/defaults/defaultconfig.goEnableTLS: false
    by default; client auth config exists but is unenforced server-side.
  • Shipped example deployments binding the broker without auth:
    deployments/examples/ocis_full/ocis.yml,
    deployments/examples/ocis_multi/docker-compose.yml
    (NATS_NATS_HOST: 0.0.0.0, and OCIS_INSECURE defaulting true in
    ocis_multi).

Downstream trust (context, fix tracked separately — see "Out of scope"):
vendor/github.com/owncloud/reva/v2/pkg/storage/utils/decomposedfs/decomposedfs.go
acts on PostprocessingFinished / RevertRevision / CleanUpload with only a
non-secret MountID comparison (skipped when empty).

Impact

  • Integrity / Availability (and malware delivery): a party able to publish
    to the bus can forge postprocessing verdicts (antivirus bypass, finalize
    unscanned/infected content), force-delete or revert arbitrary users'
    uploads, and spoof notifications/SSE.
  • Prerequisites: ability to reach the NATS port. In the default
    single-binary deployment this is 127.0.0.1 (internal only); in the shipped
    multi-service example topologies the broker is bound to 0.0.0.0 with no
    authentication, reachable by any peer on the network / any co-resident
    container, or via an internal request-forgery foothold.
  • Suggested severity: Critical wherever the bus is reachable; the absent
    broker authentication is a systemic root cause that applies to every
    deployment. CVSS:3.1 (proposed)
    AV:A/AC:L/PR:N/UI:N/S:C/C:L/I:H/A:H — adjust on review.

Proposed fix

Primary (this PR, oCIS):

  1. Wire server-side authentication into the embedded NATS server. Add an
    authorization option to services/nats/pkg/server/nats/{options,nats}.go
    and set it in services/nats/pkg/command/server.go from the existing
    Nats auth config (the same credentials clients already send via
    OCIS_EVENTS_AUTH_USERNAME / OCIS_EVENTS_AUTH_PASSWORD / token), so the
    broker actually rejects unauthenticated clients. Make the broker refuse to
    start (or log a prominent warning, per maintainer preference) when bound to
    a non-loopback host without credentials/TLS.
  2. Harden the shipped example deployments: do not bind the broker to 0.0.0.0
    without credentials; document the network-isolation/credentials requirement;
    stop defaulting OCIS_INSECURE=true in ocis_multi.

Backwards compatibility / risk

  • Deployments that already set OCIS_EVENTS_AUTH_* keep working (the server
    now enforces what clients already send). Deployments that relied on an
    anonymous bus must set credentials — call this out clearly in the changelog
    and upgrade notes.
  • Single-binary loopback default is unaffected functionally; the start-up
    guard only triggers for non-loopback binds without credentials.

Test plan

  • Unit: server rejects a client connecting with no/incorrect credentials when
    auth is configured; accepts correct credentials.
  • Integration: oCIS services connect successfully with OCIS_EVENTS_AUTH_*
    set; an external client without credentials cannot subscribe or publish.
  • Start-up guard: broker bound to 0.0.0.0 without credentials triggers the
    refuse/warn behaviour; loopback default still starts cleanly.
  • Regression: full upload → postprocessing → download flow works with auth on.

Nils Putnins / OffSeq Cybersecurity
npu@offseq.com / https://offseq.com / https://radar.offseq.com

The embedded NATS server was constructed without any authentication option,
so any client able to reach the port could subscribe to and publish forged
internal events (postprocessing/antivirus verdicts, upload finalize/revert,
notifications). Clients already authenticate via OCIS_EVENTS_AUTH_USERNAME/
OCIS_EVENTS_AUTH_PASSWORD, but the server never enforced them.

- add AuthUsername/AuthPassword to the nats service config (symmetric
  OCIS_EVENTS_AUTH_* env vars)
- add a server-side Auth option and wire it into the server command
- warn when the broker is bound to a non-loopback address without auth
- require event-bus credentials in the ocis_full and ocis_multi example
  deployments and stop defaulting OCIS_INSECURE=true in ocis_multi
@thistehneisen thistehneisen force-pushed the security/nats-event-bus-auth branch from d2035e5 to db18919 Compare May 15, 2026 19:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant