Back to skill

Security audit

IMAP/SMTP Email - Maddy Fix

Security checks for vulnerabilities and agentic risk

Overview

This email skill is mostly transparent about reading and sending mail, but it stores powerful mailbox credentials locally and has a file-write containment weakness users should review before installing.

Install only if you are comfortable giving the skill mailbox read access and send-as-email authority. Prefer app passwords or provider authorization codes, limit ALLOWED_READ_DIRS and ALLOWED_WRITE_DIRS to narrow folders, avoid downloading attachments into directories writable by other processes, and review npm dependency resolution before running setup.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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 (2)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/imap.js:16
Finding

Attachment download allowlist can be bypassed through symbolic links

Content
View full analysis
path.resolve(d.replace(/^~/, os.homedir())) ); const allowed = allowedDirs.some(dir => resolved === dir || resolved.startsWith(dir + path.sep) ); if (!allowed) { throw new Error(`Access denied: '${dirPath}' is outside allowed write directories`); } return resolved; } ``` The validated path is subsequently used without checking for symbolic links: ```javascript const filePath = path.join(resolvedDir, sanitizeFilename(attachment.filename)); fs.writeFileSync(filePath, attachment.content); ``` ### Technical Analysis The destination allowlist is enforced through lexical normalization with `path.resolve()`. This removes path traversal components such as `..`, but it does not resolve symbolic links or establish where the filesystem will ultimately write the data. Consequently, a directory located lexically beneath an allowed directory can be a symbolic link to a location outside that directory. The final attachment path may also already be a symbolic link. Because `fs.writeFileSync()` follows symbolic links by default, either condition can redirect the write outside `ALLOWED_WRITE_DIRS`. The filename sanitization prevents direct `../` traversal but does not mitigate symlink-based redirection or a time-of-check/time-of-use replacement between validation and writing. ### Attack Path 1. The configuration permits attachment writes to a directory such as `~/Downloads`. 2. A local attacker o ...[truncated 1319 chars]
Remediation
View remediation

T08 · Insecure Dependencies

Note
Location
package.json:12
Finding

Unpinned npm dependencies make installation dependent on mutable registry content

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (45)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The description presents a combined IMAP/SMTP capability set, but the provided code only covers SMTP sending-related behavior. It creates an SMTP transporter with nodemailer, sends messages, supports attachments and file-based subject/body loading, tests the SMTP connection by sending a test email, and lists configured accounts. There is no IMAP client usage, no mailbox access, no message retrieval/search, and no read/unread state modification in the supplied chunk. Multiple-account support is only loosely reflected by listing configured accounts, not by actual per-command account switching in this code. Therefore the code chunk materially underimplements the declared purpose, making the description inaccurate for this supplied code.

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 103)May include surrounding context.

md
node scripts/imap.js --account work check

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
node scripts/imap.js --account work check

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
node scripts/imap.js --account work check

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
node scripts/imap.js --account work check

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
node scripts/imap.js --account work check

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
node scripts/imap.js --account work check

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
node scripts/imap.js --account work check

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
node scripts/imap.js --account work check

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
node scripts/imap.js --account work check

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
node scripts/smtp.js --account work send --to foo@bar.com --subject Hi --body Hello

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
node scripts/smtp.js --account work send --to foo@bar.com --subject Hi --body Hello

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
node scripts/smtp.js --account work send --to foo@bar.com --subject Hi --body Hello

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
node scripts/smtp.js --account work send --to foo@bar.com --subject Hi --body Hello

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
node scripts/smtp.js --account work send --to foo@bar.com --subject Hi --body Hello

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
node scripts/smtp.js --account work send --to foo@bar.com --subject Hi --body Hello

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
node scripts/smtp.js --account work send --to foo@bar.com --subject Hi --body Hello

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
node scripts/smtp.js --account work send --to foo@bar.com --subject Hi --body Hello

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/config.js (reported line 9)May include surrounding context.

js
const dotenv = require('dotenv');

// Config file locations
const PRIMARY_ENV_PATH = path.join(os.homedir(), '.config', 'imap-smtp-email', '.env');
const FALLBACK_ENV_PATH = path.resolve(__dirname, '../.env');

// Find the .env file: primary location first, then fallback

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/config.js (reported line 10)May include surrounding context.

js
const dotenv = require('dotenv');

// Config file locations
const PRIMARY_ENV_PATH = path.join(os.homedir(), '.config', 'imap-smtp-email', '.env');
const FALLBACK_ENV_PATH = path.resolve(__dirname, '../.env');

// Find the .env file: primary location first, then fallback

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/imap.js (reported line 95)May include surrounding context.

js
const dotenv = require('dotenv');

// Config file locations
const PRIMARY_ENV_PATH = path.join(os.homedir(), '.config', 'imap-smtp-email', '.env');
const FALLBACK_ENV_PATH = path.resolve(__dirname, '../.env');

// Find the .env file: primary location first, then fallback

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/smtp.js (reported line 67)May include surrounding context.

js
const dotenv = require('dotenv');

// Config file locations
const PRIMARY_ENV_PATH = path.join(os.homedir(), '.config', 'imap-smtp-email', '.env');
const FALLBACK_ENV_PATH = path.resolve(__dirname, '../.env');

// Find the .env file: primary location first, then fallback

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/config.js (reported line 12)May include surrounding context.

js
const PRIMARY_ENV_PATH = path.join(os.homedir(), '.config', 'imap-smtp-email', '.env');
const FALLBACK_ENV_PATH = path.resolve(__dirname, '../.env');

// Find the .env file: primary location first, then fallback
function findEnvPath() {
  if (fs.existsSync(PRIMARY_ENV_PATH)) return PRIMARY_ENV_PATH;
  if (fs.existsSync(FALLBACK_ENV_PATH)) return FALLBACK_ENV_PATH;

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/config.js (reported line 67)May include surrounding context.

js
const PRIMARY_ENV_PATH = path.join(os.homedir(), '.config', 'imap-smtp-email', '.env');
const FALLBACK_ENV_PATH = path.resolve(__dirname, '../.env');

// Find the .env file: primary location first, then fallback
function findEnvPath() {
  if (fs.existsSync(PRIMARY_ENV_PATH)) return PRIMARY_ENV_PATH;
  if (fs.existsSync(FALLBACK_ENV_PATH)) return FALLBACK_ENV_PATH;

Credential Access

High
Category
Privilege Escalation
Confidence
96% confidence
Finding

The script is explicitly designed to create a .env file under the user's config directory and later populate it with email credentials, including IMAP_PASS and SMTP_PASS. In the context of an email skill, these secrets can grant direct mailbox access and the ability to send mail as the user, making credential disclosure especially sensitive and high-impact.

Content

Scanner excerpt · setup.sh (reported line 6)May include surrounding context.

sh
# IMAP/SMTP Email Skill Setup Helper

CONFIG_DIR="$HOME/.config/imap-smtp-email"
CONFIG_FILE="$CONFIG_DIR/.env"

echo "================================"
echo "  IMAP/SMTP Email Skill Setup"

Static analysis

Detected: suspicious.exposed_secret_literal

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
scripts/imap.js:78