Security Self-Audit

简体中文

This is a maintainer self-audit for people deciding whether to point Codex Quota Monitor at sensitive CLIProxyAPI and Codex OAuth state. It is not a third-party audit or a claim that deployment is risk-free. It is a map of what the monitor reads, where that data can go, what the project promises not to persist or expose, and how to verify those claims locally.

For a more structured asset, boundary, and abuse-path view, see the threat model.

Threat Model

The monitor is designed for a trusted operator running a self-hosted dashboard near an existing CPA deployment. This is an operational security model, not a hosted SaaS security model: the project relies on local binding, least-privilege runtime configuration, secret redaction, and an external authenticated access layer when the dashboard is shared. It does not implement built-in user login, RBAC, multi-tenant isolation, or user access audit logs. The main assets are:

In scope:

Out of scope:

Data Flow

Input Why it is used Destination Persistence
managementBaseUrl Read CPA management endpoints for auth inventory, usage, routing, logs, and health. Local CPA endpoint configured by the operator. Derived status and counters may appear in API/UI/history.
CPA management key Adds Authorization: Bearer <key> to CPA management requests. Legacy manual_quota_refresh_auth = "management-key" deployments also use it for the protected manual direct-quota refresh action. The configured CPA management URL, and legacy inbound /api/v1/quota/refresh verification. The key value should not be serialized to API/UI/history/metrics/logs. Browser storage is off by default and only available in legacy management-key refresh mode when allow_browser_key_storage is enabled.
Manual refresh UI token Authorizes the default browser POST /api/v1/quota/refresh action without exposing the CPA management key. Rendered page bootstrap and inbound /api/v1/quota/refresh verification. Generated in memory at process start and embedded only in the served HTML page; not printed by print-config, API JSON, history, metrics, or logs.
Codex auth files Optional direct quota sampling from auth-file access_token and account id. https://chatgpt.com/backend-api/wham/usage. Token values should not be serialized to API/UI/history/metrics/logs.
SQLite state DB Stores Trends, ETA, Audit, and Stats time-series inputs from dashboard snapshots. Local path configured by --state-db or the NixOS module. Account labels, status, quota, and usage metadata are persisted.
Benchmark summary Displays calibration results in Trends. Local summary.json path. Summary fields are shown in the dashboard.

The HTTP API is mostly read-only, but it is not an authentication boundary. The Host and Origin checks reduce accidental or cross-origin exposure; they do not identify users or replace a login/access layer. The default POST /api/v1/quota/refresh action verifies an in-page refresh token before queuing a provider-facing refresh, so browser users do not need the CPA management key. Setting manual_quota_refresh_auth = "none" removes that action check and should be limited to trusted local deployments.

Treat /api/v1/status, /api/v1/stats, /api/v1/recommendations, /api/v1/diagnostics, /api/v1/alerts, and /metrics as sensitive operational metadata even when secret values are redacted. LAN or reverse-proxy deployments must explicitly list the browser hostname/IP through --allowed-host or the NixOS module allowedHosts option.

Security Claims

These claims are intended to be testable in the repository:

Local Verification

Run the normal test suite before trusting a change:

nix develop -c python3 -m unittest discover -s tests -v
nix develop -c python3 -m build

Check that resolved config and doctor output do not print secret values:

codex-quota-monitor print-config \
  --management-base-url http://127.0.0.1:8317 \
  --management-key-file /path/to/management-key \
  --gateway-health-url http://127.0.0.1:8317/healthz \
  --state-db off

codex-quota-monitor doctor --json \
  --management-base-url http://127.0.0.1:8317 \
  --management-key-file /path/to/management-key \
  --gateway-health-url http://127.0.0.1:8317/healthz \
  --auth-dir /path/to/auth-files \
  --state-db off

After starting the service, inspect the read-only outputs for an exact secret string that only exists in your key or auth file:

secret='replace-with-a-test-only-secret-string'
curl -fsS http://127.0.0.1:4515/api/v1/status > /tmp/cqm-status.json
curl -fsS http://127.0.0.1:4515/api/v1/recommendations > /tmp/cqm-recommendations.json
curl -fsS http://127.0.0.1:4515/api/v1/diagnostics > /tmp/cqm-diagnostics.json
curl -fsS http://127.0.0.1:4515/api/v1/alerts > /tmp/cqm-alerts.json
curl -fsS http://127.0.0.1:4515/metrics > /tmp/cqm-metrics.txt
grep -R --fixed-strings "$secret" /tmp/cqm-status.json /tmp/cqm-recommendations.json /tmp/cqm-diagnostics.json /tmp/cqm-alerts.json /tmp/cqm-metrics.txt

The grep command should print no matches. Use a throwaway test secret for this check; do not paste real auth tokens or management keys into issue reports.

Before sharing support artifacts, create redacted copies instead of editing the original files:

codex-quota-monitor redact /tmp/cqm-status.json --secret "$secret" >/tmp/cqm-status-redacted.json
codex-quota-monitor redact /path/to/history.sqlite3 --output /tmp/history-redacted.sqlite3 --secret "$secret"
codex-quota-monitor redact /path/to/benchmark/summary.json --output /tmp/summary-redacted.json --secret "$secret"

For a staged support directory, run a dry-run summary first. Directory and multi-path redaction only modifies files when --apply is present:

codex-quota-monitor redact /tmp/cqm-support --secret "$secret"
codex-quota-monitor redact /tmp/cqm-support --secret "$secret" --apply

The dry-run JSON reports how many supported JSON, JSONL, CSV, text/Markdown, and SQLite files would change. Use --apply only on copied support artifacts, not on live auth directories, live history databases, or benchmark directories that the service is still writing.

Deployment Rules For New Users

Residual Risks

The monitor still sees sensitive material by design. A local attacker who can read the monitor process memory, read the auth directory, read the management key file, or control the configured CPA or proxy endpoint can exfiltrate secrets. Exposed dashboard endpoints can reveal account labels, plan tiers, quota timing, recent model activity, and service health even without raw token values. Keep the runtime local and narrowly permissioned, and review every new field added to API, metrics, history, benchmark, or logs as a privacy change.