Back to skill

Security audit

M365 Spam Manager

Security checks for vulnerabilities and agentic risk

Overview

This skill does what it claims at a high level, but its mailbox-changing commands can run without the confirmations its documentation promises.

Review this skill carefully before installing. It is not showing clear malicious intent, but it can alter Outlook or Exchange mailbox state without the confirmations its documentation describes. Use only with a Microsoft profile you trust, avoid running undocumented bulk commands unless you understand the effects, and prefer dry-run or manual review workflows until the move and labeling commands require explicit approval.

Vulnerability Patterns
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (4)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/move-to-inbox.mjs:20
Finding

Message is moved to Inbox without the documented user confirmation

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/move-to-learning.mjs:20
Finding

Learning-folder creation and message movement occur without user confirmation

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/check-spam.mjs:6
Finding

Spam-check command defaults to live bulk mutations and modifies categories during dry-run mode

Content
View full analysis
c.displayName === 'Spam'); const okCat = existingCats.find(c => c.displayName === 'OK'); let spamCatId = spamCat?.id; let okCatId = okCat?.id; if (!spamCatId) { const created = await graphFetch(categoriesUrl, { method: 'POST', token, headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ displayName: 'Spam', color: 'preset0' }), }); spamCatId = created.id; console.log('✅ Created category: Spam'); } if (!okCatId) { const created = await graphFetch(categoriesUrl, { method: 'POST', token, headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ displayName: 'OK', color: 'preset7' }), }); okCatId = created.id; console.log('✅ Created category: OK'); } ``` Only message labeling is conditionally suppressed: ```js if (dryRun) { console.log(`[DRY RUN] Would label "${m.subject?.slice(0,40)}..." as ${label} (score: ${score})`); if (isSpam) spamCount++; else okCount++; continue; } // Update categories const newCats = [...existing, label]; await graphFetch(`${base}/messages/${encodeURIComponent(m.id)}`, { method: 'PATCH', token, headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ categories: newCats }), }); if (isSpam) spamCount++; else okCount++; console.log(`✅ Labeled: ${label} (score ${score}) - ${m.subject?.slice(0,40)}...`); ``` ### Technical Analysis The command defaults ...[truncated 1767 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Note
Location
scripts/analyze.mjs:148
Finding

Attacker-controlled email fields are printed without terminal control-character sanitization

Content
View full analysis
0) { console.log(' Reasons: ' + reasons.join(', ')); } console.log(''); ``` From `scripts/check-spam.mjs`: ```js if (dryRun) { console.log(`[DRY RUN] Would label "${m.subject?.slice(0,40)}..." as ${label} (score: ${score})`); if (isSpam) spamCount++; else okCount++; continue; } ``` ```js console.log(`✅ Labeled: ${label} (score ${score}) - ${m.subject?.slice(0,40)}...`); ``` ### Technical Analysis Message senders and subjects originate from received email and must be treated as untrusted. The scripts interpolate these values directly into terminal output. Applying `slice()` limits length but does not remove ANSI escape sequences or C0/C1 control characters. If such characters survive email processing and Microsoft Graph normalization, a compatible terminal may interpret them rather than display them literally. This can alter colors, move or erase the cursor, create deceptive hyperlinks, or visually overwrite surrounding audit results. This issue affects presentation integrity rather than granting direct code execution in the reviewed implementation. ### Attack Path 1. An attacker sends an email with a crafted sender or subject containing terminal control or ANSI escape sequences. 2. The message reaches the target mailbox's Junk folder. 3. The user runs the analyzer or spam-check command in a terminal. 4. Microsoft Graph returns the crafted field, assuming it survives upstream normalization. 5. The script prints it without escaping. 6. The terminal interprets the sequence, allow ...[truncated 469 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (7)

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
86% confidence
Finding

This is a true autonomous-decision risk because the skill advertises 'Automatic mode (no confirmation)' for taking mailbox actions based on heuristic spam scoring rather than deterministic truth. The skill context makes this more dangerous, not less, because email classification is error-prone and the affected resource is a real Exchange mailbox, including potentially shared mailboxes.

Content

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

node skills/m365-spam-manager/scripts/move-to-learning.mjs --profile tom-business-mail --mailbox radman@e-ola.com --id <MSG_ID>

text

### Automatic mode (no confirmation)

```bash
# Auto-clean: move high-confidence spam to learning, medium to review

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The skill explicitly supports an automatic mode that performs mailbox-moving actions without per-item confirmation, which can modify a user's mailbox state at scale. In the context of email security workflows, false positives are common, so unattended moves can misclassify legitimate mail and cause loss of visibility, missed business communications, or training-folder pollution.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
81% confidence
Finding

This code persists the MSAL token cache back to the local filesystem with fs.writeFileSync, which is a safety-relevant file write involving authentication material. In this file there is no confirmation prompt, logging, or comment warning the user that token data may be updated on disk.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

The graphFetch helper performs outbound HTTP requests and may attach an Authorization bearer token, which can transmit user or system data to remote services. This file contains no confirmation, logging, or explanatory comment warning that requests and credentials may be sent over the network.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

This script accesses mailbox contents via Microsoft Graph and prints sender addresses, subjects, folder names, and risk annotations directly to stdout without any built-in warning, consent prompt, masking, or output-safety controls. In an agent/skill context, that can expose sensitive email metadata to logs, calling processes, terminals, or downstream tools, increasing the chance of unintended disclosure of private communications.

Content

No source excerpt is available for this finding.

Known Vulnerable Dependency: uuid==8.3.2 — 1 advisory(ies): CVE-2026-41907 (uuid: Missing buffer bounds check in v3/v5/v6 when buf is provided)

Low
Category
Supply Chain
Confidence
87% confidence
Finding

The lockfile pins uuid to 8.3.2, which the supplied finding identifies as affected by a bounds-check issue in v3/v5/v6 when a caller provides a buf argument. Although package-lock.json alone does not prove the vulnerable API path is exercised, shipping a dependency version with a known security advisory is generally a real supply-chain risk because downstream code or transitive code may invoke the affected functions.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
88% confidence
Finding

The dependency version is specified with a caret range (^5.0.4), which permits automatic installation of newer minor and patch releases. This weakens build reproducibility and can unintentionally introduce a compromised or breaking upstream release into the skill's authentication flow, especially significant because this package handles Microsoft identity and token management.

Content

Scanner excerpt · package.json (reported line 8)May include surrounding context.

json
"type": "module",
  "description": "OpenClaw skill: Microsoft 365 spam folder manager with suspicious score calculation.",
  "dependencies": {
    "@azure/msal-node": "^5.0.4"
  }
}

Static analysis

No suspicious patterns detected.