TL;DR

praktor, a self-hosted Go service that routes Telegram messages to Claude Code agents running in Docker containers, wrote uploaded Telegram documents to a path built from the attacker-controlled filename, so a filename with .. segments landed anywhere in the agent's persistent workspace volume, including CLAUDE.md, skill, hook and configuration files the agent reads on every run. With the default allow_from: [] every Telegram user can message the bot, so no authentication is needed. The vendor advisory (2026-06-26) and CVE-2026-62331 (GitHub CNA, 2026-10-30, CVSS 3.1 8.2) say the fix is 0.9.1. The GitHub Advisory Database reviewed it on 2026-11-03. Upgrade, and set telegram.allow_from to the user ids you trust.

What happened

The vendor advisory. GHSA-48v2-6jcm-fc99, published 2026-06-26 by the maintainer, describes praktor as an agent system with a Telegram bot interface where each agent runs a Claude agent against a persistent workspace volume mounted at /workspace/agent. Two upload sites in internal/telegram/bot.go concatenated the attacker-controlled filename into the destination path, and path.Join collapsed the ../ sequences, so a filename such as ../../../CLAUDE.md resolved to the root of the workspace volume instead of uploads/. "Because the agent reads from and operates on this workspace across runs, an attacker can plant or overwrite files it later consumes", which the advisory calls stored instruction injection into the agent's execution surface. Reachability: "By default, allow_from: [] means all users are allowed. The only precondition is that a user can message the bot." The fix in PR 228 applies path.Base() to the filename at both sites and makes WriteVolumeBytes reject any path that escapes the volume. The workaround is to restrict telegram.allow_from. The reporter is credited as tonghuaroot, who the advisory says supplied the root-cause analysis and verified the fix.

The record. CVE-2026-62331 (GitHub_M CNA, published 2026-10-30 19:00 UTC, four months after the vendor advisory) carries the same description, affected < 0.9.1, CVSS 3.1 8.2 AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:H/A:N, CWE-22, and references the advisory, PR 228, the fix commit and the v0.9.1 release tag. The database row appeared on 2026-11-03 in the agent and claude queries as a reviewed Go advisory for github.com/mtzanidakis/praktor. The repository has 45 stars and 10 forks when read. The README describes a single Go binary deployed with Docker Compose, with the agent image built locally because it cannot be distributed pre-built, and a Mission Control UI on port 8080.

Why it is here. The scale is small. The shape is not: a chat-channel front end to a coding agent, with no allowlist by default, where a file upload becomes the agent's instructions on its next run. The corpus has the same shape at larger scale in the AGENTS.md-in-Downloads and GitSpawn files. This one adds the remote write primitive. A workspace that persists across runs is the agent's memory, and anything that can write into it writes the agent's future behaviour.

Am I affected?

  1. Version: the praktor binary or image you built; anything before 0.9.1 (the advisory lists 0.9.0 and earlier, including HEAD at commit 3902d29).
  2. Config: telegram.allow_from in config/praktor.yaml. An empty list means every Telegram user who finds the bot can message it and upload to it.
  3. Workspace: list the root of each praktor-wk-<workspace> volume for files outside uploads/ that your team did not create, in particular CLAUDE.md, .claude/ skills and hooks, and any file whose name starts with ...

If you are affected

  • Upgrade to 0.9.1 or later and set telegram.allow_from to explicit user ids.
  • Treat any workspace with an unexplained file at its root as a compromised agent: read the planted instructions, assume every run since the file's modification time followed them, and review what those agents had credentials for. See if your local AI agent was exploited.
  • Rotate the Claude Code credentials and any tokens mounted into the agent containers.

Prevention

  • A chat bot that drives a coding agent is an internet-facing API. Allowlist senders before the first run. See agent sandboxing.
  • Do not let uploads land in the directory the agent reads instructions from. Keep uploads/ on a separate mount.

Sources