Labels: security, bug, pro, priority:high
File: src/tether/pro/license.py:253 (staleness gate), :270-294 (unconditional local refresh), enforcement src/tether/runtime/server.py:~2903, soft-fail src/tether/pro/heartbeat.py:~79
Description. load_license never consults the server revocation list; it checks a local last_heartbeat_at, then rewrites it to now on every successful load. The signed payload excludes last_heartbeat_at, so it's freely editable even on a v2 license. Runtime heartbeat network failures are swallowed as "soft failures" and retried silently.
Why it matters. The 24 h freshness gate can never trip as long as the process restarts periodically, and an operator who firewalls the license endpoint keeps a revoked license fully working. Revocation only bites if the worker is reachable and returns 403.
Tasks.
Dedup. PR #229 preserves signed fields but does not add revocation enforcement or server-confirmed freshness.
Labels:
security,bug,pro,priority:highFile:
src/tether/pro/license.py:253(staleness gate),:270-294(unconditional local refresh), enforcementsrc/tether/runtime/server.py:~2903, soft-failsrc/tether/pro/heartbeat.py:~79Description.
load_licensenever consults the server revocation list; it checks a locallast_heartbeat_at, then rewrites it tonowon every successful load. The signed payload excludeslast_heartbeat_at, so it's freely editable even on a v2 license. Runtime heartbeat network failures are swallowed as "soft failures" and retried silently.Why it matters. The 24 h freshness gate can never trip as long as the process restarts periodically, and an operator who firewalls the license endpoint keeps a revoked license fully working. Revocation only bites if the worker is reachable and returns 403.
Tasks.
Dedup. PR #229 preserves signed fields but does not add revocation enforcement or server-confirmed freshness.