Skip to content

security(spp_dci_compliance): _post_init_hook presets the well-known token as an accepted server API token [Severity: Medium] #328

Description

@gonzalesedwin1123

Follow-up discovered while fixing #326 (client-side retained bearer token on upgrade). This is a separate module and a distinct exposure on the server side, deliberately left out of PR #326's scope.

Severity: Medium (effective) — High if the module is network-reachable

  • CVSS 3.1 (if installed on a reachable deployment): 8.2 / HighAV:N/AC:L/PR:N/UI:N/S:U/C:H/I:L/A:N. The accepted token is published in this repo, signature verification is turned off, so a remote, unauthenticated attacker can make authenticated DCI server calls and read registry data (PII) via search/query.
  • Effective rating: Medium, because exposure is gated on a deployment precondition, not on attacker effort: spp_dci_compliance is explicitly test-only (application: False, auto_install: False, Alpha), is not part of any default/production install, and the module itself emits a security warning for these flags (spp_dci_compliance/models/security_warning.py). The finding is the same fail-open pattern as security(dci): purge stale compliance bearer token on upgrade #326: nothing prevents the dangerous state — it relies on the module never being installed outside a test harness.
  • Confidentiality: High (registry PII readable). Integrity: Low (subscribe/callback manipulation). Availability: None.

Finding

spp_dci_compliance/__init__.py _post_init_hook (runs on module install) hardcodes the same well-known secret as an accepted server API token, and grants the public user registry read:

# Set accepted Bearer tokens (matches spdci-compliance test suite default)
config.set_param("dci.api_tokens", "compliance-test-api-key-12345")
...
config.set_param("dci.allow_unsigned_requests", "true")
config.set_param("dci.allow_http_callbacks", "true")
config.set_param("dci.allow_internal_callback_ips", "true")
# public_user added to spp_registry.group_registry_viewer

Grounding (server-side controls these params drive):

  • dci.api_tokens is the DCI server's accepted inbound bearer-token allow-list — spp_dci_server/middleware/signature.py:361. Presetting it to the public value means the server accepts that public token as valid auth. (Note: leaving it empty would instead reject requests when dci.api_tokens_required=true, so presetting the known value is strictly worse than not setting it.)
  • dci.allow_unsigned_requests=true disables request signature verification server-side — spp_dci_server/middleware/signature.py:114.
  • dci.allow_http_callbacks / dci.allow_internal_callback_ips relax callback destination controls.

Where #326 concerned the DCI client re-using a known outbound credential, this makes the DCI server accept that same publicly-known token as a valid inbound bearer credential, with signatures off — so anyone who knows the token could authenticate to the DCI server API on any deployment where this module is installed.

Why it's arguably intended (and why it still needs review)

spp_dci_compliance is compliance-test infrastructure meant to run against a mock registry in a test harness — the hardcoded token matches the spdci-compliance suite default, and security_warning.py already surfaces the relaxed flags. The risk is the same fail-open pattern #326 addressed: an accidental install in a real deployment silently opens an unauthenticated/known-credential surface.

Options to consider

  • A — fail closed like the client module: don't preset dci.api_tokens (require the operator to set a token), don't relax signature/callback/IP checks by default, and gate the whole hook behind an explicit opt-in flag or test_enable.
  • B — keep test defaults but guard install: refuse to apply these params outside a test context, mirroring spp_dci_client_compliance's _compliance_enabled gate and fail-closed data source; optionally escalate the existing security_warning.py into a hard block outside test mode.
  • C — accept as-is if this module is guaranteed test-only and never shipped to production installs — but document that constraint explicitly and keep the security warning.

Decision needed

Which option, and whether to also add a migration to strip dci.api_tokens/relaxed flags from any DB that already installed this module (parallel to #326's migration).

Source: observed at spp_dci_compliance/__init__.py:31 while working internal/plans/sec-dci-compliance-stale-bearer-token.md. Related: #326.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions