Back to skill

Security audit

IMAP SMTP Email

Security checks for vulnerabilities and agentic risk

Overview

The email skill is mostly transparent, but its optional watcher can expose raw mailbox credentials to a spawned OpenClaw process and has some local file-safety weaknesses.

Review before installing if this mailbox is sensitive. The basic IMAP/SMTP functions are purpose-aligned, but avoid enabling the optional watcher unless you trust the spawned OpenClaw environment with mailbox credentials. Use an app-specific password, restrict allowed read/write directories, avoid symlinks in those directories, and run setup only in a trusted local account.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
Findings (3)

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/email-watch-lite.js:371
Finding

OpenClaw Agent Subprocess Inherits Raw Email Credentials

Content
View full analysis

Vulnerability Details

File Location: scripts/email-watch-lite.js:371-376
Related Credential Loading: scripts/email-watch-lite.js:6, scripts/imap.js:30-33
Vulnerability Type: Excessive subprocess privilege and secret exposure
Risk Level: High

Vulnerable Code

js
const { checkEmails } = require('./imap');

Importing scripts/imap.js executes the following credential-loading code:

js
const EMAIL_ENV_DEFAULT = path.join(os.homedir(), '.openclaw', 'credentials', 'imap-smtp-mail.env');
const EMAIL_ENV_FILE = process.env.EMAIL_ENV_FILE || EMAIL_ENV_DEFAULT;
require('dotenv').config({ path: EMAIL_ENV_FILE });

The resulting environment is then passed without filtering to the AI-agent subprocess:

js
const agentOutput = execFileSync(openclawBin, agentArgs, {
  cwd: WORKSPACE_ROOT,
  encoding: 'utf8',
  stdio: 'pipe',
  env: process.env,
  timeout: CHILD_PROCESS_TIMEOUT_MS,
});

Technical Analysis

Requiring ./imap loads the configured dotenv file into the watcher's global process.env. This environment can contain IMAP_PASS, SMTP_PASS, mailbox usernames, server addresses, and unrelated secrets inherited from the parent OpenClaw process.

The watcher subsequently starts openclaw agent with env: process.env, granting the entire subprocess direct access to every loaded credential. The agent needs to process pending email UIDs and can invoke the narrowly scoped mail scripts, but it does not need unrestricted possession of raw IMAP and SMTP passwords.

Although execFileSync avoids shell command injection, it does not mitigate secret inheritance. Any compromised OpenClaw binary, loaded plugin, agent-accessible local tool, or other code executing in that subprocess can read the credentials directly from its environment.

Attack Path

  1. The watcher imports scripts/imap.js.
  2. scripts/imap.js loads `~/.openclaw/credentials/imap-smtp-mail.e ...[truncated 1042 chars]
Remediation
View remediation

Remediation Suggestions

  • Replace env: process.env with an explicit allowlist containing only variables required by the OpenClaw CLI, such as PATH, HOME, locale settings, and narrowly selected OpenClaw configuration.
  • Explicitly remove IMAP_PASS, SMTP_PASS, and other secret-bearing variables before creating the subprocess.
  • Avoid loading the credential file into the watcher's global environment. Refactor IMAP configuration loading so credentials are held in a local configuration object.
  • Prefer a narrowly scoped local broker or capability interface that allows the agent to fetch designated UIDs without exposing mailbox credentials.
  • Run the optional watcher under a dedicated account with minimal filesystem and environment access.
  • Document the subprocess trust boundary and test that child processes cannot observe email passwords.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/imap.js:42
Finding

Attachment Write Allowlist Can Be Bypassed Through a Symlinked Ancestor

Content
View full analysis

Vulnerability Details

File Location: scripts/imap.js:42-47, scripts/imap.js:487-496
Vulnerability Type: Symlink-based filesystem allowlist bypass
Risk Level: Medium

Vulnerable Code

The path validator falls back to lexical resolution when the requested directory does not yet exist:

js
let resolved;
try {
  resolved = fs.realpathSync(expanded);
} catch {
  resolved = path.resolve(expanded);
}

The validated path is subsequently created and used for attachment writes:

js
const resolvedDir = validateWritePath(outputDir);
if (!fs.existsSync(resolvedDir)) {
  fs.mkdirSync(resolvedDir, { recursive: true });
}

const downloaded = [];

for (const attachment of parsed.attachments) {
  if (specificFilename && attachment.filename !== specificFilename) {
    continue;
  }
  if (attachment.content) {
    const filePath = path.join(resolvedDir, sanitizeFilename(attachment.filename));
    fs.writeFileSync(filePath, attachment.content);

Technical Analysis

fs.realpathSync correctly resolves symbolic links only when the complete target path exists. When the requested output directory is nonexistent, the function catches the error and uses path.resolve, which performs only lexical normalization and does not resolve symlink components.

An output path can therefore appear to be under an allowed directory during validation while an existing ancestor is a symlink pointing outside that directory. fs.mkdirSync and fs.writeFileSync then follow the symlink during actual filesystem operations.

Filename sanitization prevents direct ../ traversal in attachment names, but it does not protect the destination directory from symlink traversal.

Attack Path

  1. An attacker or another local process creates a symlink under an allowed directory, for example workspace/tmp/link pointing to an external writable directory.
  2. The attacker requests an attachment do ...[truncated 1066 chars]
Remediation
View remediation

Remediation Suggestions

  • Resolve the nearest existing ancestor of a nonexistent destination and verify that its canonical path remains inside an allowed directory.
  • Reject destination paths containing symlink components, for example by checking each component with lstatSync.
  • Create the destination directory and then call realpathSync again before writing any attachment.
  • Repeat the allowlist check on the final canonical directory immediately before every write.
  • Open files using restrictive and exclusive flags where overwriting is not intended.
  • Consider using directory file descriptors and platform-supported no-follow semantics to reduce time-of-check/time-of-use races.
  • Add regression tests covering symlinks directly under allowed directories and symlinks in nested ancestor paths.

T09 · Insecure Skill Coding Practices

Warning
Location
setup.sh:145
Finding

Credential Setup Uses Non-Atomic, Symlink-Following File Creation

Content
View full analysis

Vulnerability Details

File Location: setup.sh:145-177
Vulnerability Type: Insecure secret-file creation
Risk Level: Medium

Vulnerable Code

bash
# Create credentials file
CRED_DIR="${HOME}/.openclaw/credentials"
CRED_FILE="${CRED_DIR}/imap-smtp-mail.env"
mkdir -p "$CRED_DIR"
cat > "$CRED_FILE" << EOF
# IMAP Configuration
IMAP_HOST=$IMAP_HOST
IMAP_PORT=$IMAP_PORT
IMAP_USER=$EMAIL
IMAP_PASS=$PASSWORD
IMAP_TLS=$IMAP_TLS
IMAP_REJECT_UNAUTHORIZED=$REJECT_UNAUTHORIZED
IMAP_MAILBOX=INBOX

# SMTP Configuration
SMTP_HOST=$SMTP_HOST
SMTP_PORT=$SMTP_PORT
SMTP_SECURE=$SMTP_SECURE
SMTP_USER=$EMAIL
SMTP_PASS=$PASSWORD
SMTP_FROM=$EMAIL
SMTP_FROM_NAME=$FROM_NAME
SMTP_REPLY_TO=$EMAIL
SMTP_REJECT_UNAUTHORIZED=$REJECT_UNAUTHORIZED
IMAP_SAVE_SENT=true

# File access whitelist (security)
ALLOWED_READ_DIRS=${ALLOWED_READ_DIRS:-$HOME/.openclaw/workspace,$HOME/.openclaw/workspace/exports,$HOME/.openclaw/workspace/out,$HOME/.openclaw/workspace/tmp}
ALLOWED_WRITE_DIRS=${ALLOWED_WRITE_DIRS:-$HOME/.openclaw/workspace/exports,$HOME/.openclaw/workspace/tmp}
EOF

echo ""
echo "Created credentials at: $CRED_FILE"
chmod 600 "$CRED_FILE"

Technical Analysis

Shell redirection creates or truncates the credential file before chmod 600 is executed. Its initial permissions are determined by the process umask, so under a permissive umask the plaintext mailbox password can temporarily be readable by other local users.

The credentials directory is created without explicitly enforcing mode 700. In addition, shell redirection follows an existing symbolic link at imap-smtp-mail.env. The script does not verify that the target is a regular file owned by the current user before overwriting it.

The final chmod 600 is useful but occurs too late to make initial creation secure and can itself operate on the target of a preexisting symlink.

Attack Path

Possible exploitation ...[truncated 987 chars]

Remediation
View remediation

Remediation Suggestions

  • Set umask 077 before creating either the credential directory or file.
  • Create the credential directory with mode 700 and verify that it is owned by the current user.
  • Refuse to proceed if the credential path is a symbolic link or is not a regular user-owned file.
  • Write credentials to a securely created temporary file in the same directory, set mode 600, and atomically rename it into place.
  • Use a safe exclusive-creation mechanism to prevent races with another local process.
  • Apply cleanup traps so temporary files containing secrets are removed on errors or interruption.
  • Avoid retaining the password in shell variables longer than necessary and unset it after successful setup.
Vulnerability Patterns
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (57)

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding

The code clearly matches much of the read-oriented portion of the description: it connects to IMAP, checks unread/all mail, fetches full messages, searches by common criteria, lists mailboxes, parses attachments (including PDF/Excel/CSV extraction), and downloads attachments with write-path restrictions. However, the declared description says the skill can both read and send email via IMAP/SMTP and mentions an optional inbox watcher that can forward alerts via OpenClaw CLI. None of the provided code performs SMTP operations, composes/sends mail, watches for new mail events, or invokes OpenClaw. Additionally, the code includes mailbox-state mutation functions (mark read/unread), which are not mentioned in the declared description. Because important declared capabilities are absent and one undeclared capability is present, this is a description/behavior mismatch.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The description presents a broader IMAP/SMTP mail skill focused on reading inboxes and sending mail. This specific code chunk is mainly an SMTP send CLI plus helper features: draft approval preview, SMTP test, reply metadata via IMAP fetch, saving sent copies to IMAP, and local contact resolution. It also accesses local contacts and file contents, which are undeclared resource interactions beyond basic SMTP sending. While some IMAP-related support exists, the primary behavior here is not full inbox reading/search/downloading/watching as described. Therefore the supplied code chunk does not accurately match the declared description.

Content

No source excerpt is available for this finding.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 24)May include surrounding context.

md
- `node scripts/imap.js ...`

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 114)May include surrounding context.

md
- `node scripts/imap.js ...`

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 121)May include surrounding context.

md
- `node scripts/imap.js ...`

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 128)May include surrounding context.

md
- `node scripts/imap.js ...`

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 137)May include surrounding context.

md
- `node scripts/imap.js ...`

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 159)May include surrounding context.

md
- `node scripts/imap.js ...`

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 166)May include surrounding context.

md
- `node scripts/imap.js ...`

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 173)May include surrounding context.

md
- `node scripts/imap.js ...`

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 180)May include surrounding context.

md
- `node scripts/imap.js ...`

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 296)May include surrounding context.

md
- `node scripts/imap.js ...`

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 25)May include surrounding context.

md
- `node scripts/smtp.js ...`

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 189)May include surrounding context.

md
- `node scripts/smtp.js ...`

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 196)May include surrounding context.

md
- `node scripts/smtp.js ...`

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 203)May include surrounding context.

md
- `node scripts/smtp.js ...`

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 204)May include surrounding context.

md
- `node scripts/smtp.js ...`

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 211)May include surrounding context.

md
- `node scripts/smtp.js ...`

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 218)May include surrounding context.

md
- `node scripts/smtp.js ...`

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 225)May include surrounding context.

md
- `node scripts/smtp.js ...`

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 234)May include surrounding context.

md
- `node scripts/smtp.js ...`

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 241)May include surrounding context.

md
- `node scripts/smtp.js ...`

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 251)May include surrounding context.

md
- `node scripts/smtp.js ...`

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 258)May include surrounding context.

md
- `node scripts/smtp.js ...`

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 270)May include surrounding context.

md
- `node scripts/smtp.js ...`