T09 · Insecure Skill Coding Practices
- Location
scripts/collect_beeper_daily.py:247- Finding
Decrypted Private Messages Written to an Unsafe Predictable Temporary File
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This skill is a disclosed Beeper messaging integration, but it asks for durable access to private chats and ships several unsafe install, storage, persistence, and encryption-default choices that need review before use.
Install only on a trusted, dedicated machine or account. Review the installer before running it, pin and verify bbctl and Python dependencies, avoid the legacy client.py send command, do not use /tmp for private digests or plaintext key exports, and enable the sync daemon only if you accept persistent background access to new private-message keys.
scripts/collect_beeper_daily.py:247Decrypted Private Messages Written to an Unsafe Predictable Temporary File
scripts/import_key_backup.py:321Plaintext Megolm Session Keys Exported Without Enforced File Protection
install.sh:32Mutable Remote bbctl Executable Downloaded Without Integrity Verification
install.sh:53Security-Critical Python Dependencies Installed Without Version or Hash Pinning
scripts/nio_client.py:378Message Encryption Keys Shared with Unverified Matrix Devices
scripts/client.py:169Legacy Client Exposes a Non-E2EE Plaintext Message Send Path
The README documents that the skill relies on long-lived high-value credentials and stores them locally, including a Beeper recovery key and access token. In this skill's context, those credentials enable broad access to private communications across many bridged platforms, so compromise of the host or accidental exposure of these files could give an attacker durable cross-network message access and decryption capability.
|---|---|---|
| Beeper password | User's head / password manager | Master secret |
| Beeper Recovery Key | `~/.secrets/beeper-recovery-key.txt` (600) | Master secret (decrypts cross-signing keys) |
| `bbctl` access token | `~/.config/bbctl/config.json` (600) | Device-scoped credential |
| Olm/Megolm store | `~/.local/share/clawd-matrix/` (700) | Device-scoped credential |
If the recovery key ever leaks, **regenerate it from Beeper Desktop** (Settings → name → ⌄ → Reset Recovery Code) and re-run `bootstrap_crosssign.py` on each agent device.
The code matches only one narrow portion of the description: bootstrapping cross-signing from the Beeper recovery key. It does not implement the broader advertised behavior of interacting with chats across Facebook Messenger, WhatsApp, Instagram, LinkedIn, Twitter/X, Signal, Telegram, Discord, etc., nor does it expose a wrapper for message operations or run a sync daemon. Instead, its actual purpose is specifically Matrix/Beeper cryptographic account setup: reading local secret files, deriving secret-storage keys, decrypting cross-signing seeds, signing the current device, and uploading signatures. Because the declared description presents a much broader end-user messaging capability while this code chunk performs only specialized E2EE/bootstrap tasks, the description does not accurately represent what this supplied code chunk actually does.
The declared description promises a much broader and more sophisticated skill than the supplied code implements. The code is narrowly a CLI wrapper around Matrix client-server endpoints using urllib, with commands for whoami, list-chats, send, and history. It depends on preexisting credentials in ~/.config/bbctl/config.json but contains no installation logic for bbctl, no encryption setup, no recovery-key or cross-signing bootstrap, and no background sync/decryption service. It also does not implement search, and the visible network handling covers Facebook/Messenger, Instagram, WhatsApp, LinkedIn, Twitter/X, and Discord aliases, but not other declared networks like Signal or Telegram. The core purpose is related to Beeper messaging access, but the actual behavior materially falls short of several key declared capabilities, so this is a mismatch.
The declared purpose describes a broad, full-featured Beeper integration layer with setup/installation steps, E2EE bootstrap, ongoing sync/decryption, and interactive messaging operations including sending. The supplied code chunk is much narrower: it is a batch reporting script for collecting recent activity from selected bridged networks, optionally decrypting some message content, and saving a markdown summary locally. While it is related to Beeper and reading message activity, the primary purpose is materially different and several claimed capabilities are absent. Therefore this is a description-behavior mismatch.
The declared description presents a broad cross-network messaging skill whose purpose is to send/read chats via Beeper bridges, set up E2EE, run a sync daemon, and expose a unified wrapper. The supplied code chunk instead performs a narrower but sensitive cryptographic maintenance task: restoring historical Matrix encryption keys from server-side backup into a local store. While this can support the overall E2EE/history-reading functionality of the larger skill, the code chunk itself does not implement the declared primary user-facing behavior of reading/sending/searching chats across social networks. It also includes an undeclared capability to export decrypted session data to a file. Therefore the description does not accurately represent what this specific code chunk actually does.
The declared description presents a broad multi-network messaging skill built on Beeper/Matrix, including setup and a unified messaging wrapper. This code chunk instead performs a narrow, security-related task: interactive SAS key verification between this client and Beeper Desktop. While device verification is tangentially related to E2EE setup, the actual code does not implement the declared core functionality of reading/sending/searching messages across networks, nor the described installation/bootstrap/daemon behavior. The code’s primary purpose is materially different from the declared purpose, so this is a mismatch.
The skill explicitly depends on a Beeper access token stored in a local config file, which grants access to the user's bridged messaging environment. Any skill that reads or uses such a token has high-value credential access and, if compromised or over-permissioned, could impersonate the user across multiple messaging networks.
├── sync_daemon.py ← long-running sync (systemd) → new Megolm sessions
└── verify_interactive.py ← fallback: SAS verification via Beeper Desktop
▼
bbctl + access token (~/.config/bbctl/config.json)
▼
https://matrix.beeper.com/_hungryserv/<user> (Matrix CS API)
▼
This section states that user login stores an access token in ~/.config/bbctl/config.json and that the nio client relies on it. Because that token enables authenticated messaging actions, compromise of the host, logs, or overbroad skill access could result in account takeover-like behavior across all bridged services.
bbctl login
The user enters their Beeper credentials. This stores an access token at `~/.config/bbctl/config.json`. That token is all the nio client needs.
Verify:
```bash
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).
# Unsign the device: Beeper UI → Settings → Devices → sign out the bbctl device
# Then on the host:
rm -rf ~/.local/share/clawd-matrix # nio store
rm -rf ~/.config/bbctl # bbctl access token
rm ~/.secrets/beeper-recovery-key.txt # recovery key
rm ~/.secrets/beeper-desktop-token # desktop API token, if ever created
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).
# Unsign the device: Beeper UI → Settings → Devices → sign out the bbctl device
# Then on the host:
rm -rf ~/.local/share/clawd-matrix # nio store
rm -rf ~/.config/bbctl # bbctl access token
rm ~/.secrets/beeper-recovery-key.txt # recovery key
rm ~/.secrets/beeper-desktop-token # desktop API token, if ever created
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).
# Unsign the device: Beeper UI → Settings → Devices → sign out the bbctl device
# Then on the host:
rm -rf ~/.local/share/clawd-matrix # nio store
rm -rf ~/.config/bbctl # bbctl access token
rm ~/.secrets/beeper-recovery-key.txt # recovery key
rm ~/.secrets/beeper-desktop-token # desktop API token, if ever created
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).
# Unsign the device: Beeper UI → Settings → Devices → sign out the bbctl device
# Then on the host:
rm -rf ~/.local/share/clawd-matrix # nio store
rm -rf ~/.config/bbctl # bbctl access token
rm ~/.secrets/beeper-recovery-key.txt # recovery key
rm ~/.secrets/beeper-desktop-token # desktop API token, if ever created
# Keep ~/bin/bbctl if you might re-use bbctl.
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).
rm -rf ~/.local/share/clawd-matrix # nio store rm -rf ~/.config/bbctl # bbctl access token rm ~/.secrets/beeper-recovery-key.txt # recovery key rm ~/.secrets/beeper-desktop-token # desktop API token, if ever created
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).
rm -rf ~/.local/share/clawd-matrix # nio store rm -rf ~/.config/bbctl # bbctl access token rm ~/.secrets/beeper-recovery-key.txt # recovery key rm ~/.secrets/beeper-desktop-token # desktop API token, if ever created
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
Beeper/Matrix client wrapper for Clawd.
Uses the Beeper hungryserv Matrix homeserver via the standard client-server API.
Reads the access token from bbctl's config (~/.config/bbctl/config.json).
Connected networks (bridged in Beeper cloud):
- facebook (Messenger)
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
Beeper/Matrix client wrapper for Clawd.
Uses the Beeper hungryserv Matrix homeserver via the standard client-server API.
Reads the access token from bbctl's config (~/.config/bbctl/config.json).
Connected networks (bridged in Beeper cloud):
- facebook (Messenger)
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
Beeper/Matrix client wrapper for Clawd.
Uses the Beeper hungryserv Matrix homeserver via the standard client-server API.
Reads the access token from bbctl's config (~/.config/bbctl/config.json).
Connected networks (bridged in Beeper cloud):
- facebook (Messenger)
The README prominently markets unified messaging, sending, reading history, and digest generation across multiple personal networks, but it does not place an equally prominent privacy warning near those capabilities. In an agent skill context, this omission matters because an integrator may enable the skill without appreciating that it can aggregate and transmit highly sensitive private cross-platform communications.
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.
bbctl whoami # sanity check: all bridges RUNNING
# 2. Save your recovery key (never commit this!)
mkdir -p ~/.secrets && chmod 700 ~/.secrets
echo 'YOUR RECOVERY KEY HERE' > ~/.secrets/beeper-recovery-key.txt
chmod 600 ~/.secrets/beeper-recovery-key.txt
The README recommends enabling a persistent user-level sync daemon that continuously maintains message decryption state and inbound access. In an agent skill, that persistence increases exposure because the capability remains active beyond a single user-approved session and can silently retain access to newly delivered encrypted conversations.
scripts/sync_daemon.py wraps matrix-nio's sync_forever in a supervised loop with exponential backoff and consumes these to_device events as they arrive. Running it under systemd keeps the store always up-to-date.
systemctl --user enable --now clawd-beeper-sync.service
journalctl --user -u clawd-beeper-sync -f
The skill requests or implies powerful capabilities including shell execution, network access, and file read/write, but does not declare an explicit permission or allowed-tools scope. In a skill that handles messaging, local secrets, access tokens, and recovery keys, missing scope boundaries increases the chance of overbroad agent actions and unintended access to sensitive resources.
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.
- Linux (tested on Ubuntu 24.04). macOS should work too.
- `python3` with `venv`
- `uv` (or plain `pip`) to create the venv
- `libolm-dev` (package for Olm/Megolm crypto)
- `ffmpeg` (optional, for media attachments later)
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.
mkdir -p ~/.secrets && chmod 700 ~/.secrets
cat > ~/.secrets/beeper-recovery-key.txt <<EOF
EsUC HBcy scrf uiTy DTU2 rvEB Jmgj 9Cpa D6V2 z7Vk ZrU9 9RMh
EOF
The documented direct write access to personal chats across bridged networks confirms that the skill can perform persistent authenticated actions on the user's behalf. In this context, persistence is more dangerous because the same authenticated environment may remain available across sessions, enabling unintended or unauthorized messaging if controls fail.
## Safety rules for the agent
This skill gives the agent direct write access to the user's personal chats
on every bridged network. The agent MUST treat every `send` as a privileged
operation:
The instruction to log every outgoing send into workspace memory creates an unnecessary retention trail for sensitive private communications. If workspace files are accessible to other tools, users, backups, or sync systems, this can expose conversation metadata or content beyond the original messaging platform.
No suspicious patterns detected.