Back to skill

Security audit

imap-smtp-email

Security checks for vulnerabilities and agentic risk

Overview

The skill is a real email tool, but it needs review because its dependency/install chain and attachment download boundary have concrete security weaknesses.

Install only if you are comfortable giving the skill access to your email account and letting it send mail on your behalf. Prefer an app-specific password, keep ALLOWED_READ_DIRS and ALLOWED_WRITE_DIRS narrow, avoid symlinked download directories, review outgoing email commands before running them, and update or pin dependencies from trusted registries before use.

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)

T08 · Insecure Dependencies

Warning
Location
package-lock.json:382
Finding
Nodemailer Dependency Retrieved from a Non-Official Package Registry<![CDATA[ ## Vulnerability Details **File Location**: `package-lock.json:382-387`; dependency installation is triggered by `setup.sh:17-20` **Vulnerability Type**: Third-party dependency supply-chain exposure **Risk Level**: Medium ### Vulnerable Code ```bash # Install Node.js dependencies SKILL_DIR="$(cd "$(dirname "$0")" && pwd)" if [ ! -d "$SKILL_DIR/node_modules" ]; then echo "Installing dependencies..." (cd "$SKILL_DIR" && npm install --production) echo "" fi ``` ```json "node_modules/nodemailer": { "version": "9.0.3", "resolved": "https://registry.npmmirror.com/nodemailer/-/nodemailer-9.0.3.tgz", "integrity": "sha512-n+YP+NKwR5zRWa60k3GiQ6Q3B4KXCoAw40dAKeCtYn020iNN74aWK2liXIC3ZEATeGql7we3tE3t8QwhY0eskw==", "license": "MIT-0", "engines": { "node": ">=6.0.0" } } ``` ### Technical Analysis The setup process automatically invokes `npm install --production`. The lockfile instructs npm to retrieve the primary Nodemailer package from `registry.npmmirror.com`, while the other dependencies are predominantly retrieved from the official npm registry. Nodemailer is a security-sensitive dependency because it receives SMTP credentials, message contents, recipient addresses, and local attachment paths. Using an additional package-distribution operator expands the supply-chain trust boundary beyond the official npm registry. The pinned SHA-512 integrity value materially limits exploitation: control of the mirror alone is not sufficient to replace the package transparently because npm should reject content that does not match the lockfile hash. Successful package substitution would therefore also require modification of the lockfile integrity value, compromise or bypass of npm integrity verification, or delivery of a package already matching the trusted digest. The non-official source nevertheless creates an avoidable dependency-delivery and availability risk. ### Attack Path 1. A user runs `bash setup.sh`. 2. If `node_modules` is absent, the ...[truncated 1215 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Regenerate the lockfile so all packages are resolved from the official npm registry: ```bash npm config set registry https://registry.npmjs.org/ rm -rf node_modules package-lock.json npm install --package-lock-only ``` 2. Review the resulting lockfile and confirm that no unexpected registry domains remain. 3. Replace `npm install --production` with deterministic installation: ```bash npm ci --omit=dev ``` 4. If dependency lifecycle scripts are not required, further reduce installation-time execution exposure: ```bash npm ci --omit=dev --ignore-scripts ``` 5. Preserve and verify lockfile integrity values in source control. 6. Add CI checks that reject lockfile `resolved` URLs outside an approved registry allowlist. 7. Periodically audit the dependency tree, especially packages that process credentials, email content, or attachments. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/imap.js:55
Finding
Attachment Download Allowlist Can Be Bypassed Through Symlinked Directories<![CDATA[ ## Vulnerability Details **File Location**: `scripts/imap.js:55-73`, with the unsafe write at `scripts/imap.js:467-474` **Vulnerability Type**: Symlink traversal and insufficient filesystem boundary validation **Risk Level**: Medium ### Vulnerable Code ```javascript function validateWritePath(dirPath) { if (!config.allowedWriteDirs.length) { throw new Error('ALLOWED_WRITE_DIRS not set in .env. Attachment download is disabled.'); } const resolved = path.resolve(dirPath.replace(/^~/, os.homedir())); const allowedDirs = config.allowedWriteDirs.map(d => 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 as follows: ```javascript const resolvedDir = validateWritePath(outputDir); if (!fs.existsSync(resolvedDir)) { fs.mkdirSync(resolvedDir, { recursive: true }); } const downloaded = []; for (const attachment of parsed.attachments) { // If specificFilename is provided, only download matching attachment if (specificFilename && attachment.filename !== specificFilename) { continue; } if (attachment.content) { const filePath = path.join(resolvedDir, sanitizeFilename(attachment.filename)); fs.writeFileSync(filePath, attachment.content); downloaded.push({ filename: attachment.filename, path: filePath, size: attachment.size, }); } } ``` ### Technical Analysis `validateWritePath` performs only lexical normalization with `path.resolve()`. It does not canonicalize the destination with `fs.realpathSync()` and does not inspect path components for symbolic links. Consequently, a path may appear to be under an approved directory while resolving through a symlink to a location outside that directory. For example: ```tex ...[truncated 2269 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Canonicalize every configured allowlist root with `fs.realpathSync()` before comparison. 2. Require the destination directory to exist, then canonicalize it with `fs.realpathSync()` and compare the canonical destination against canonical allowlist roots. 3. Reject destination paths containing symbolic-link components. Walk each path component with `fs.lstatSync()` and fail if any component is a symlink. 4. Revalidate immediately before opening each output file to reduce time-of-check/time-of-use race exposure. 5. Where supported, open files using no-follow semantics such as `O_NOFOLLOW`. 6. Avoid overwriting existing files unless explicitly requested. Use exclusive creation flags such as `wx`: ```javascript fs.writeFileSync(filePath, attachment.content, { flag: 'wx', mode: 0o600 }); ``` 7. Canonicalize the parent directory again after creating it and before writing. 8. Consider creating a dedicated, application-owned attachment directory with restrictive permissions instead of permitting arbitrary subdirectories. A hardened validation flow should resemble: ```javascript function canonicalDirectory(directory) { const expanded = directory.replace(/^~/, os.homedir()); const lexical = path.resolve(expanded); const stat = fs.lstatSync(lexical); if (!stat.isDirectory() || stat.isSymbolicLink()) { throw new Error('Destination must be a real directory, not a symbolic link'); } return fs.realpathSync(lexical); } function validateWritePath(dirPath) { if (!config.allowedWriteDirs.length) { throw new Error('Attachment download is disabled'); } const destination = canonicalDirectory(dirPath); const allowedRoots = config.allowedWriteDirs.map(canonicalDirectory); const allowed = allowedRoots.some(root => destination === root || destination.startsWith(root + path.sep) ); if (!allowed) { throw new Error('Destination is outside allowed write directories'); } return destination; ...[truncated 129 chars]
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (53)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The description mostly matches the IMAP-related read/search/mark functionality implemented here, but it overstates the code's capabilities in material ways. Most importantly, there is no SMTP or send-email logic in this code chunk, despite the declared purpose explicitly promising sending emails with attachments. Additionally, the code writes attachments to local disk, which is a resource-access capability not mentioned in the description. Finally, while the description says it supports multiple accounts, this chunk's operational commands use a single configured IMAP account from config; it only exposes account listing, not clear multi-account selection or simultaneous support in the shown code. Therefore the declared description does not accurately represent the supplied code chunk.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The declared description presents an operational IMAP/SMTP email skill. However, this code chunk does not implement email access or message operations at all. Its sole purpose is local configuration migration: it reads a legacy env file, parses credentials and server settings, detects providers, builds account config blocks, handles allowed read/write directory settings, and emits a new config format. While this may support the broader email skill during setup, the actual behavior of this chunk is materially different from the declared end-user capability, so this chunk is a mismatch against the stated description.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The description presents a combined IMAP/SMTP email skill with both mailbox-reading and message-sending capabilities. However, this code chunk is an SMTP CLI only. Its implemented commands are 'send', 'test', and 'list-accounts'. It creates an SMTP transporter, sends mail, optionally loads subject/body/HTML from local files, attaches files from allowed directories, and can send a test message to the configured account. There is no code here for connecting to IMAP, listing or searching messages, checking unread mail, fetching email contents, or changing read/unread state. While account listing and attachment sending are consistent with part of the description, the core declared read/IMAP capabilities are absent from the provided code, making the description materially broader than the actual behavior of this chunk.

Ae1

High
Category
analysis-evasion
Content
node scripts/imap.js --account work check
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node scripts/imap.js --account work check
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node scripts/imap.js --account work check
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node scripts/imap.js --account work check
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node scripts/imap.js --account work check
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node scripts/imap.js --account work check
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node scripts/imap.js --account work check
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node scripts/imap.js --account work check
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node scripts/imap.js --account work check
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node scripts/smtp.js --account work send --to foo@bar.com --subject Hi --body Hello
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node scripts/smtp.js --account work send --to foo@bar.com --subject Hi --body Hello
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node scripts/smtp.js --account work send --to foo@bar.com --subject Hi --body Hello
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node scripts/smtp.js --account work send --to foo@bar.com --subject Hi --body Hello
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node scripts/smtp.js --account work send --to foo@bar.com --subject Hi --body Hello
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node scripts/smtp.js --account work send --to foo@bar.com --subject Hi --body Hello
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node scripts/smtp.js --account work send --to foo@bar.com --subject Hi --body Hello
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node scripts/smtp.js --account work send --to foo@bar.com --subject Hi --body Hello
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Known Vulnerable Dependency: linkify-it==5.0.0 — 2 advisory(ies): CVE-2026-48801 (LinkifyIt#match scan loop has quadratic algorithmic complexity); CVE-2026-59887 (linkify-it: Quadratic-complexity DoS via the `mailto:` validator scan-loop on at)

High
Category
Supply Chain
Confidence
96% confidence
Finding
This lockfile includes linkify-it 5.0.0, which is flagged for quadratic-complexity denial-of-service issues during link parsing, including mailto handling. In an email skill, attacker-controlled email bodies and headers are realistic inputs, so parsing untrusted message content can trigger CPU exhaustion and service degradation.

Known Vulnerable Dependency: nodemailer==8.0.5 — 8 advisory(ies): CVE-2026-82661 (Nodemailer: CRLF injection in Nodemailer List-* header comments allows arbitrary); GHSA-2x7j-588g-ccc2 (Nodemailer: Quadratic (O(n²)) time complexity in addressparser allows remote den); GHSA-8m3c-c648-2xjj (Nodemailer: resolveContent() on a MailMessage bypasses disableFileAccess/disable) +5 more

High
Category
Supply Chain
Confidence
98% confidence
Finding
This package-lock contains nodemailer 8.0.5 as a transitive dependency under mailparser, and the listed advisories include CRLF/header injection, resource-exhaustion, and content resolution bypass issues. Because this skill processes and sends email, malformed attacker-supplied addresses, headers, or message structures are directly relevant and could lead to denial of service, header manipulation, or unsafe file/content access behavior depending on how the library is used upstream.

Known Vulnerable Dependency: nodemailer==9.0.3 — 4 advisory(ies): GHSA-2x7j-588g-ccc2 (Nodemailer: Quadratic (O(n²)) time complexity in addressparser allows remote den); GHSA-8m3c-c648-2xjj (Nodemailer: resolveContent() on a MailMessage bypasses disableFileAccess/disable); GHSA-cc9r-2j5m-2m83 (Nodemailer: Recipient-domain validation bypass via RFC 5322 comment mis-parsing ) +1 more

High
Category
Supply Chain
Confidence
97% confidence
Finding
The direct dependency nodemailer 9.0.3 is flagged for multiple high-severity issues, including address parsing denial-of-service and security-control bypasses around content and recipient validation. In a skill whose main purpose is SMTP email sending, these flaws are especially relevant because untrusted recipient fields, headers, and message composition data may come from users or parsed emails.

Known Vulnerable Dependency: semver==5.3.0 — 1 advisory(ies): CVE-2022-25883 (semver vulnerable to Regular Expression Denial of Service)

High
Category
Supply Chain
Confidence
85% confidence
Finding
semver 5.3.0 is affected by a ReDoS issue, but here it appears only as a transitive dependency of utf7 used by imap. The vulnerability is real in the dependency tree, though this specific skill context makes exploitability less direct unless attacker-controlled semver expressions are somehow passed into that code path.

Known Vulnerable Dependency: nodemailer==9.0.3 — 4 advisory(ies): GHSA-2x7j-588g-ccc2 (Nodemailer: Quadratic (O(n²)) time complexity in addressparser allows remote den); GHSA-8m3c-c648-2xjj (Nodemailer: resolveContent() on a MailMessage bypasses disableFileAccess/disable); GHSA-cc9r-2j5m-2m83 (Nodemailer: Recipient-domain validation bypass via RFC 5322 comment mis-parsing ) +1 more

High
Category
Supply Chain
Confidence
97% confidence
Finding
The package depends on nodemailer 9.0.3, which is flagged with multiple published advisories, including issues affecting parsing, validation, and safety controls. In an email skill that sends mail and may handle attachments or untrusted recipient/address content, these flaws are more dangerous because they sit directly in the core message construction and delivery path.

Static analysis

No suspicious patterns detected.