Back to skill

Security audit

M365 Calendar (Graph)

Security checks for vulnerabilities and agentic risk

Overview

This Microsoft 365 calendar skill is mostly purpose-aligned, but it stores sensitive OAuth tokens with weak filesystem safeguards and has a profile path handling flaw that merits review before install.

Review this skill before installing on shared or multi-user machines. Use only trusted profile names, protect ~/.openclaw/secrets/m365-calendar with owner-only permissions, avoid raw-token import unless necessary, prefer explicit timezone arguments, and consider pinning dependencies with a lockfile before relying on it for business calendars.

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 (2)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/_lib.mjs:15
Finding

Profile Name Path Traversal Enables Filesystem Access Outside the Secrets Directory

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/_lib.mjs:9
Finding

OAuth Token and Configuration Files Are Created Without Restrictive Permissions

Content
View full analysis
{ if (cache) ctx.tokenCache.deserialize(cache); }, afterCacheAccess: async (ctx) => { if (ctx.cacheHasChanged) { cache = ctx.tokenCache.serialize(); fs.writeFileSync(cachePath, cache, 'utf8'); } }, }, }, ``` Raw OAuth tokens are likewise written without an explicit mode in `scripts/import-raw-token.mjs:20-24`: ```js const raw = JSON.parse(fs.readFileSync(file, 'utf8')); if (!raw.access_token) throw new Error('Raw token file missing access_token'); // Store as a simple JSON cache format that _graph.mjs can consume when present. fs.writeFileSync(cachePath, JSON.stringify(raw, null, 2) + '\n', 'utf8'); ``` The normal token-refresh path also rewrites the cache without enforcing permissions in `scripts/_graph.mjs:31-40`: ```js cache: { cachePlugin: { beforeCacheAccess: async (ctx) => ctx.tokenCache.deserialize(cache), afterCacheAccess: async (ctx) => { if (ctx.cacheHasChanged) { cache = ctx.tokenCache.serialize(); fs.writeFileSync(cachePath, cache, 'utf8'); } }, }, }, ``` ### Technica ...[truncated 2398 chars]
Remediation
View remediation
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • 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
Findings (6)

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

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

Content

Scanner excerpt · references/config.md (reported line 15)May include surrounding context.

md
- `email` (optional; informational)
  - `scopes` (calendar delegated scopes)
- `~/.openclaw/secrets/m365-calendar/<profile>-token-cache.json`
  - MSAL token cache (refresh token, access token, etc.)

## Why not workspace/secrets?

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
78% confidence
Finding

Multiple usage examples and recommended commands consistently force --tz Europe/Vienna, and the workflow does not indicate that the timezone should be chosen based on the user's preference or locale. This can violate language/locale policy by implicitly steering operation to a fixed locale without opt-in.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
91% confidence
Finding

The dependency is specified with a caret range (^5.0.4) rather than being pinned to an exact version, which makes builds non-reproducible and can result in different installed versions over time. In a security-sensitive skill that handles Microsoft Graph authentication flows, this increases supply-chain risk because a newly published semver-compatible release could introduce a vulnerability or malicious code without any manifest change.

Content

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

json
"type": "module",
  "description": "OpenClaw skill: Microsoft Graph calendar automation (M365 business + consumer).",
  "dependencies": {
    "@azure/msal-node": "^5.0.4"
  }
}

Unverifiable Dependency: @azure/msal-node has 1 known advisory(ies) (CVE-2024-35255 (Azure Identity Libraries and Microsoft Authentication Library Elevation of Privi)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
84% confidence
Finding

The manifest references @azure/msal-node without an exact version pin, while the package has a known advisory in some releases, so it is not possible to verify from this file alone whether deployment will resolve to a patched or affected version. Because this skill automates Microsoft 365 calendar access via Microsoft Graph, any vulnerable authentication library could increase the risk of token handling, privilege, or account-compromise issues in a context that likely processes user credentials or delegated access.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
79% confidence
Finding

The statement at L03 suggests a strong safety property, but the rest of the document explicitly describes storing MSAL token cache files with refresh and access tokens under the user's home directory. While this does keep them out of git, it contradicts any implication that secrets are broadly protected or not persisted, which can mislead users about the actual handling of sensitive credentials.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
90% confidence
Finding

The script defaults tz to Europe/Vienna, which imposes a specific locale-related behavior unless the user explicitly overrides it. This is a natural-language/policy-style locale constraint embedded in code behavior and is not documented here as justified or optional by default.

Content

No source excerpt is available for this finding.