T09 · Insecure Skill Coding Practices
- Location
scripts/imap.sh:88- Finding
Unrestricted forwarded arguments can override trusted IMAP connection settings
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This email-reading skill is mostly coherent, but its wrapper can expose mailbox credentials through unsafe argument forwarding and credential-file handling.
Install only if you are comfortable granting an agent access to the configured mailbox. Prefer OpenClaw SecretRef or short-lived environment injection over plaintext credential files, use a narrowly scoped app password, avoid shared or monitored machines, and do not allow user-supplied myl connection/authentication flags until the wrapper validates or rejects them. Pin or review the myl dependency before use.
scripts/imap.sh:88Unrestricted forwarded arguments can override trusted IMAP connection settings
scripts/imap.sh:26Credential file is executed as unrestricted shell code
scripts/imap.sh:127IMAP password is exposed through process command-line metadata
references/installation.md:47Security-sensitive third-party mail client is installed from mutable, unpinned sources
references/troubleshooting.md:148Manual OpenSSL troubleshooting procedure can expose the mailbox password
Tool calls are chained to bypass individual safety checks or escalate capabilities beyond what any single tool call would allow.
# Install pipx itself if missing (Debian/Ubuntu)
sudo apt update && sudo apt install -y pipx
pipx ensurepath
# Install myl
YARA rule matched a known malware signature (reverse shell, backdoor, ransomware, C2 framework, or info stealer).
ll myl
On macOS:
```bash
brew install pipx
pipx ensurepath
pipx install myl
After pipx ensurepath, the user may need to restart their shell or source ~/.bashrc / source ~/.zshrc for myl to appear on PATH.
pip --user — fallback when pipx isn't availablepip install --user myl
The binary lands in ~/.local/bin, which must be on PATH. If not:
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc
# One-shot run without installing
nix run github:pschmitt/myl -- --help
# Or add to a flake
git clone https://github.com/pschmitt/myl.git
cd myl
pipx install .
If the agent runs inside a Docker sandbox (OpenClaw agents.defaults.sandbox.docker), myl must be installed inside the container as well — the host bin doesn't satisfy the in-sandbox requirement. Add to setupCommand:
{
"agents": {
"defaults": {
YARA rule matched a known malware signature (reverse shell, backdoor, ransomware, C2 framework, or info stealer).
t — file a bug against OpenClaw with metadata.openclaw excerpt + your skills.entries config (passwords redacted).
myl: command not found (non-OpenClaw)OpenClaw shouldn't load this skill without myl because of requires.bins: ["myl"]. If you see this on Claude Code or another runtime:
pip install --user but ~/.local/bin is not in PATH. Add it:
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc && source ~/.bashrc
pipx but pipx ensurepath was never run, or the shell wasn't restarted.pip show myl or pipx list to confirm.AUTHENTICATIONFAILED / Invalid credentials / LOGIN failedThe username + password combination was rejected. In order of likelihood:
The README recommends persisting IMAP credentials, including the password, in a local plaintext file under ~/.config/imap-client/credentials. Even with 600 permissions, this creates a durable secret on disk that can be exposed through local compromise, backups, endpoint telemetry, accidental inclusion in support bundles, or other user-context malware. In this skill's context, handling real mailbox credentials makes persistence more sensitive because compromise grants direct access to private email and attachments.
export IMAP_PROVIDER='yandex'
**Headless / cron / fallback** — create `~/.config/imap-client/credentials`:
```bash
mkdir -p ~/.config/imap-client
The skill explicitly instructs the agent to execute shell commands (bash {baseDir}/scripts/check_myl.sh and bash {baseDir}/scripts/imap.sh) but does not declare any tool scope such as permissions or allowed-tools. In an agent runtime, missing scope boundaries can allow unintended shell access or make the skill runnable in environments where command execution policy is not clearly constrained, increasing the blast radius if the skill or its referenced scripts are modified or abused.
The trigger description is very broad and includes generic phrases like 'check my email', 'find the email from Y', and even provider names, which can cause the skill to activate for loosely related requests. Because this skill handles mailbox access and credential-dependent shell operations, accidental invocation could prompt unnecessary credential setup, unexpected mailbox queries, or disclosure of email metadata beyond the user's precise intent.
Tool defaults are unsafe or overly permissive (e.g. disabled TLS verification, no authentication, world-writable permissions). Unsafe defaults widen the attack surface.
Then restart the agent session (or wait for the skills watcher to pick it up if skills.load.watch is enabled). The next time the agent runs the skill, IMAP_USER and IMAP_PASSWORD are already in the environment.
Permissions matter. ~/.openclaw/openclaw.json should not be world-readable:
chmod 600 ~/.openclaw/openclaw.json
Tool defaults are unsafe or overly permissive (e.g. disabled TLS verification, no authentication, world-writable permissions). Unsafe defaults widen the attack surface.
Then restart the agent session (or wait for the skills watcher to pick it up if skills.load.watch is enabled). The next time the agent runs the skill, IMAP_USER and IMAP_PASSWORD are already in the environment.
Permissions matter. ~/.openclaw/openclaw.json should not be world-readable:
chmod 600 ~/.openclaw/openclaw.json
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.
Permissions matter. ~/.openclaw/openclaw.json should not be world-readable:
chmod 600 ~/.openclaw/openclaw.json
Use apiKey with a SecretRef for stronger isolation. OpenClaw supports pulling the password from a separate source rather than inlining it as plaintext in the JSON:
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.
Permissions matter. ~/.openclaw/openclaw.json should not be world-readable:
chmod 600 ~/.openclaw/openclaw.json
Use apiKey with a SecretRef for stronger isolation. OpenClaw supports pulling the password from a separate source rather than inlining it as plaintext in the JSON:
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.
Permissions matter. ~/.openclaw/openclaw.json should not be world-readable:
chmod 600 ~/.openclaw/openclaw.json
Use apiKey with a SecretRef for stronger isolation. OpenClaw supports pulling the password from a separate source rather than inlining it as plaintext in the JSON:
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.
Permissions matter. ~/.openclaw/openclaw.json should not be world-readable:
chmod 600 ~/.openclaw/openclaw.json
Use apiKey with a SecretRef for stronger isolation. OpenClaw supports pulling the password from a separate source rather than inlining it as plaintext in the JSON:
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.
Permissions matter. ~/.openclaw/openclaw.json should not be world-readable:
chmod 600 ~/.openclaw/openclaw.json
Use apiKey with a SecretRef for stronger isolation. OpenClaw supports pulling the password from a separate source rather than inlining it as plaintext in the JSON:
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.
Permissions matter. ~/.openclaw/openclaw.json should not be world-readable:
chmod 600 ~/.openclaw/openclaw.json
Use apiKey with a SecretRef for stronger isolation. OpenClaw supports pulling the password from a separate source rather than inlining it as plaintext in the JSON:
The skill explicitly documents storing IMAP credentials in a persistent plaintext file under ~/.config/imap-client/credentials. Even with mode 600, this creates a durable secret at rest that can be harvested by local malware, backups, accidental syncing, or other post-compromise access. In this skill context, the risk is meaningful because the stored secret grants ongoing mailbox access, which is highly sensitive.
When neither Method A nor B is convenient (e.g. cron jobs, headless workflows, CI), drop a credentials file at ~/.config/imap-client/credentials:
mkdir -p ~/.config/imap-client
cat > ~/.config/imap-client/credentials <<'EOF'
IMAP_USER='you@example.com'
IMAP_PASSWORD='app-specific-password-here'
Tool defaults are unsafe or overly permissive (e.g. disabled TLS verification, no authentication, world-writable permissions). Unsafe defaults widen the attack surface.
chmod 600 ~/.config/imap-client/credentials
The wrapper sources this file when `IMAP_USER`/`IMAP_PASSWORD` are not in the env, **but only if permissions are 600 or 400**. World-readable creds files are ignored with a warning.
To use a different path, set `IMAP_CREDENTIALS_FILE` in env.
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.
# Install pipx itself if missing (Debian/Ubuntu)
sudo apt update && sudo apt install -y pipx
pipx ensurepath
# Install myl
The documentation explicitly presents a ## Marking as seen command and notes that it mutates server state. Later, the same file states that myl is read-only, which contradicts the documented behavior because marking messages seen changes mailbox state on the server.
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.
The wrapper refuses to source ~/.config/imap-client/credentials (or $IMAP_CREDENTIALS_FILE) unless it's chmod 600 or chmod 400. Fix:
chmod 600 ~/.config/imap-client/credentials
The troubleshooting guide recommends enabling shell tracing (set -x) around execution of the IMAP wrapper. Shell tracing can echo expanded commands, arguments, and sourced values into terminal logs or session transcripts; in an email/IMAP skill, that creates a realistic risk of exposing usernames, passwords, or other sensitive environment-derived configuration during debugging.
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.
# Lookup order for credentials:
# 1. Process env vars (set by OpenClaw skills.entries.imap-client.env, or
# manually via `export` in the user's shell).
# 2. ~/.config/imap-client/credentials (must be chmod 600 or 400).
# 3. $IMAP_CREDENTIALS_FILE (override path; same perms required).
#
# Variables consumed:
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.
# Lookup order for credentials:
# 1. Process env vars (set by OpenClaw skills.entries.imap-client.env, or
# manually via `export` in the user's shell).
# 2. ~/.config/imap-client/credentials (must be chmod 600 or 400).
# 3. $IMAP_CREDENTIALS_FILE (override path; same perms required).
#
# Variables consumed:
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.
# Lookup order for credentials:
# 1. Process env vars (set by OpenClaw skills.entries.imap-client.env, or
# manually via `export` in the user's shell).
# 2. ~/.config/imap-client/credentials (must be chmod 600 or 400).
# 3. $IMAP_CREDENTIALS_FILE (override path; same perms required).
#
# Variables consumed:
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.
# Lookup order for credentials:
# 1. Process env vars (set by OpenClaw skills.entries.imap-client.env, or
# manually via `export` in the user's shell).
# 2. ~/.config/imap-client/credentials (must be chmod 600 or 400).
# 3. $IMAP_CREDENTIALS_FILE (override path; same perms required).
#
# Variables consumed:
The script sources a credentials file from a path that can be overridden by IMAP_CREDENTIALS_FILE, but it validates only the mode bits and not ownership, symlink status, or whether the path is a regular file. If an attacker can influence that environment variable or the referenced filesystem path, they may cause arbitrary shell code execution when the file is sourced, because '.' executes file contents as Bash code rather than parsing a data-only format. In a skill that handles mailbox credentials, this is more dangerous because compromise can expose both local execution context and email secrets.
CRED_FILE="${IMAP_CREDENTIALS_FILE:-$HOME/.config/imap-client/credentials}"
if [[ ( -z "${IMAP_USER:-}" || -z "${IMAP_PASSWORD:-}" ) && -f "$CRED_FILE" ]]; then
# Refuse to source a world-readable creds file. Permissions check works on
# both GNU stat (Linux) and BSD stat (macOS).
perms=$(stat -c '%a' "$CRED_FILE" 2>/dev/null || stat -f '%A' "$CRED_FILE" 2>/dev/null || echo "?")
case "$perms" in
No suspicious patterns detected.