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
COT_URL=wss://<host>:8443/takproto/1, PYTAK_TLS_CLIENT_CERT=/etc/<app>/client.pem (a real, user-managed PEM).
- Server returns 403 on the WS upgrade (e.g. cert not yet trusted, ACL, or a transient auth hiccup).
/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.
Summary
ws_factory()deletes the file referenced byPYTAK_TLS_CLIENT_CERTwhen the WebSocket handshake returns HTTP 403. The intent (per the comment) is to clear a stale enrollment cache p12, but the code deletes whateverPYTAK_TLS_CLIENT_CERTpoints at — including a user-managed PEM cert supplied for a directwss://connection. A transient/auth 403 thus destroys the operator's cert + key-adjacent file, permanently bricking the service and losing the credential.Environment
COT_URL=wss://<host>:8443/takproto/1with explicitPYTAK_TLS_CLIENT_CERT=/etc/<app>/client.pemReproduce
COT_URL=wss://<host>:8443/takproto/1,PYTAK_TLS_CLIENT_CERT=/etc/<app>/client.pem(a real, user-managed PEM)./etc/<app>/client.pemis now gone (os.removed). Next start fails with "Resource not found: PYTAK_TLS_CLIENT_CERT".Observed live: a 403 from a
wssendpoint wiped/etc/.../client.pem(and the key path), taking down the daemon.Root cause
ws_factory()(pytak/client_functions.py, ~L326):PYTAK_TLS_CLIENT_CERTis a general TLS-client knob (used by thetls://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 arbitraryPYTAK_TLS_CLIENT_CERTpath. Gate the deletion on the path being inside the cache dir (and.endswith(".p12")), or track cache-owned files explicitly.