Back to skill

Security audit

Microsoft 365

Security checks for vulnerabilities and agentic risk

Overview

This looks like a real Microsoft 365 integration, but it asks for broad write and offline access and stores reusable OAuth tokens in plaintext with inconsistent documentation.

Review carefully before installing. Use only if you are comfortable granting broad Microsoft 365 permissions, including sending mail and modifying calendars, contacts, and OneDrive files. Protect ~/.openclaw/credentials/ms365.tokens.<account>.json and ms365.env with owner-only permissions, consider a dedicated low-privilege Microsoft app/account, and revoke the Microsoft app grant if you stop using the skill or suspect token exposure.

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)

T09 · Insecure Skill Coding Practices

Error
Location
src/config.js:128
Finding

OAuth Tokens Are Stored Without Restrictive File Permissions

Content
View full analysis
0) { toSave.expires_at = Date.now() + (expiresIn * 1000); } } fs.writeFileSync(tokenPath, JSON.stringify(toSave, null, 2)); } ``` ### Technical Analysis The Skill persists Microsoft OAuth access and refresh tokens using `fs.writeFileSync` without specifying a restrictive file mode. The effective permissions therefore depend on the process umask. On systems with a common `0022` umask, a newly created token file may have mode `0644`, making it readable by other local users. The stored refresh token is a long-lived reusable credential. An attacker who reads it can submit it to Microsoft's OAuth token endpoint and obtain new access tokens without knowing the user's password. The resulting privileges include every delegated scope granted to the application. The implementation also does not verify whether the destination file is a symbolic link, whether it is owned by the current user, or whether an existing file has secure permissions before reading or overwriting it. ### Attack Path 1. A victim authenticates through the device-code flow. 2. The Skill writes the token response to `~/.openclaw/credentials/ms365.tokens.<account>.json`. 3. The token file inherits permissions from the process umask and may be readable by another local account or compromise ...[truncated 938 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
src/api.js:12
Finding

Microsoft Bearer Token Can Be Forwarded to an Unrestricted Absolute URL

Content
View full analysis
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
src/auth.js:4
Finding

OAuth Permissions Exceed the Minimum Required Scope and Are Incompletely Disclosed

Content
View full analysis
Remediation
View remediation
.json`. - How to remove local tokens and revoke the Microsoft application grant. 5. Update setup and configuration documentation to use the runtime's actual account-specific filenames. `setup.js` currently writes `config.json`, while runtime loading expects `config..json`. 6. Add automated tests that verify read-only commands do not request unrelated write scopes. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Rogue AgentSelf-Modification, Session Persistence
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (22)

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 · src/api.js (reported line 16)May include surrounding context.

js
async function callGraph(endpoint, method = 'GET', body = null) {
  const token = await getAccessToken(currentAccount);
  if (!token) throw new Error('No access token available. Login required.');

  const headers = {
    Authorization: `Bearer ${token}`,

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 · src/auth.js (reported line 84)May include surrounding context.

js
}
    }
  } catch (err) {
    console.error(`[config] Kon .env niet laden (${envPath}):`, err.message);
  }
}

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 · src/config.js (reported line 58)May include surrounding context.

js
}
    }
  } catch (err) {
    console.error(`[config] Kon .env niet laden (${envPath}):`, err.message);
  }
}

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The README tells users that OAuth tokens are stored locally in tokens.json but does not warn them to protect that file, exclude it from version control, or restrict filesystem permissions. Refresh/access tokens can grant ongoing access to mail, calendar, contacts, and OneDrive data if the file is copied, shared, or accidentally committed.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The manifest describes broader functionality including sending emails and managing calendar events, while the README's 'Functies' section lists only reading recent emails, fetching calendar items, viewing contacts, and browsing OneDrive root files. This is a semantic mismatch between the declared scope of the skill and the documented behavior of the implementation.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding

The skill declares capabilities that require environment-variable access and network communication, but it does not explicitly define a tool scope such as permissions or allowed-tools. This creates ambiguity about what the skill is authorized to do and weakens containment, especially for a skill that accesses Microsoft 365 data and uses stored credentials.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
67% confidence
Finding

The skill explicitly stores authentication tokens under the user's home directory and supports interactive and automated reuse of an account session. Persistent Microsoft 365 tokens increase the blast radius of compromise because anyone who can read those files or trigger the skill under the same user context may gain ongoing access to email, calendar, contacts, and OneDrive data.

Content

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

md
### Calendar
- **Fetch events**: `node index.js --account personal --calendar`
- **Create event**: Use interactive mode or automated scripts.

### Email
- **Read emails**: Interactive mode (option 1).

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The script's user-facing prompts and instructions are written in Dutch, which imposes a specific language on all users. There is no opt-in, fallback, or documented justification that this skill is intended only for Dutch-speaking users or a Dutch-specific environment.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

This function sends an email via the Microsoft Graph API, which is an external action affecting user data and communications. In this file there is no confirmation prompt, logging/print statement, or explanatory docstring/comment warning that the function transmits content to Microsoft Graph and causes an email to be sent.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
84% confidence
Finding

This function creates calendar events, which writes user data to an external service and changes the user's calendar state. The file does not include a confirmation prompt, user-visible log, or descriptive warning comment/docstring explaining that the operation will create an event remotely.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
85% confidence
Finding

This function issues a PATCH request to modify an existing calendar event, which is a state-changing operation on user data. There is no confirmation, user-facing log, or explanatory comment/docstring in this file to disclose that the user's calendar data will be altered.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
84% confidence
Finding

This function creates a new contact in the user's Microsoft account, which writes personal data to an external service. The code does not provide a confirmation prompt, visible disclosure, or explanatory comment/docstring warning about this remote write operation.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
85% confidence
Finding

This function patches contact data in the user's account, which is a user-data modification operation. The file lacks any user-facing warning, confirmation, or explanatory comment/docstring indicating that contact records will be changed remotely.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

This function uploads content to OneDrive using an authenticated PUT request, which writes user data to remote storage and can overwrite or create files. There is no confirmation prompt, user-facing log, or explanatory docstring/comment in this file to disclose that a remote file write is occurring.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The file contains many user-visible strings exclusively in Dutch, including errors, prompts, and status messages, but provides no opt-in, fallback, or documentation that the skill is intentionally Dutch-only. This creates a natural-language policy issue because the skill imposes a specific language on users without choice.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The code persists OAuth token material with saveTokens(data, discoveredAccountName) immediately after authentication, but this file provides no user-facing notice, consent, or storage-safety guarantees. Because the scopes include Mail, Calendar, Contacts, and Files with offline_access, stored refresh/access tokens can grant broad long-lived access if the local token store is readable by other users, malware, or backups.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
86% confidence
Finding

The code reads a credentials file from credentials/ms365.env and copies its contents into process.env, which is a sensitive operation involving credentials. While there is error logging on failure, there is no confirmation prompt, user-facing notice, or explanatory comment warning that secrets from disk will be loaded into process environment state.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

OAuth token data is written to disk in plaintext under the user's home directory without any permission hardening or encryption. In a Microsoft 365 skill, these tokens can grant access to mail, calendar, contacts, and OneDrive data, so compromise of the local filesystem could expose sensitive account data or enable account actions.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

The natural-language instructions force a specific language for all users, and the file does not indicate that Dutch is optional or that the skill is intended only for a Dutch-speaking audience. Under the policy, locale constraints should be optional or clearly justified.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
96% confidence
Finding

This code presents user-facing status and error text in both Dutch and English, such as Dutch authentication errors alongside English success messages. That imposes a language choice on users without opt-in and matches the policy category for locale/language violations.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
93% confidence
Finding

The error message Kon .env niet laden is hard-coded in Dutch, and similar Dutch-only text appears elsewhere in the file. This is a natural-language locale choice imposed by the skill without opt-in or documented region-specific justification, which can violate language/locale policy expectations.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

The message Kon JSON niet lezen/parsen is another user-visible Dutch-only string. Hard-coded locale-specific messaging across the file indicates the skill enforces a language choice rather than offering a neutral default or user preference.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.