Skip to content

wss:// 403 handler deletes user-provided PYTAK_TLS_CLIENT_CERT file (data loss) #99

Description

@ampledata

Summary

ws_factory() deletes the file referenced by PYTAK_TLS_CLIENT_CERT when the WebSocket handshake returns HTTP 403. The intent (per the comment) is to clear a stale enrollment cache p12, but the code deletes whatever PYTAK_TLS_CLIENT_CERT points at — including a user-managed PEM cert supplied for a direct wss:// connection. A transient/auth 403 thus destroys the operator's cert + key-adjacent file, permanently bricking the service and losing the credential.

Environment

  • pytak 7.3.11, aiohttp 3.14.1, Python 3.11 (Debian 12)
  • COT_URL=wss://<host>:8443/takproto/1 with explicit PYTAK_TLS_CLIENT_CERT=/etc/<app>/client.pem

Reproduce

  1. COT_URL=wss://<host>:8443/takproto/1, PYTAK_TLS_CLIENT_CERT=/etc/<app>/client.pem (a real, user-managed PEM).
  2. Server returns 403 on the WS upgrade (e.g. cert not yet trusted, ACL, or a transient auth hiccup).
  3. /etc/<app>/client.pem is now gone (os.removed). Next start fails with "Resource not found: PYTAK_TLS_CLIENT_CERT".

Observed live: a 403 from a wss endpoint wiped /etc/.../client.pem (and the key path), taking down the daemon.

Root cause

ws_factory() (pytak/client_functions.py, ~L326):

except aiohttp.WSServerHandshakeError as exc:
    if exc.status == 403:
        cert_path = config.get("PYTAK_TLS_CLIENT_CERT", "")
        if cert_path and os.path.exists(cert_path):
            pass_path = cert_path.replace(".p12", ".pass")
            for p in (cert_path, pass_path):
                os.remove(p)   # <-- deletes a USER-PROVIDED cert, not just a cache p12

PYTAK_TLS_CLIENT_CERT is a general TLS-client knob (used by the tls:// path too); it is not guaranteed to be a disposable enrollment-cache p12.

Suggested fix

Only delete certs pytak itself created in its managed enrollment cache (e.g. under ~/.pytak/certs/), never an arbitrary PYTAK_TLS_CLIENT_CERT path. Gate the deletion on the path being inside the cache dir (and .endswith(".p12")), or track cache-owned files explicitly.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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