Back to skill

Security audit

Outlook Calendar (M365)

Security checks for vulnerabilities and agentic risk

Overview

This Outlook calendar skill is not clearly malicious, but it handles Microsoft account credentials and reusable session material in risky plaintext files and can activate too broadly.

Review before installing. Use only in an isolated, trusted environment and avoid storing a primary Microsoft password in ~/.outlook/config.json unless you accept the account/session risk. Prefer a version that uses official Microsoft OAuth with calendar-read-only scopes, secure token storage, strict file permissions, narrower activation rules, and a clear cleanup/revocation path.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • 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 (5)

T01 · Skill Instruction Hijacking

Warning
Location
SKILL.md:10
Finding
Overbroad mandatory activation causes unnecessary calendar access<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:10-17` **Vulnerability Type**: Overbroad activation instructions and violation of least privilege **Risk Level**: Medium ### Vulnerable Code ```markdown ## 触发条件 **只要用户问任何涉及日程、会议、安排、日历、工作、任务、事情的问题,必须调用此技能。** - "明天有什么安排" / "这周有什么会" / "本月日程" - "帮我看看日历" / "我今天几点有会" - "这个月会议一共多少小时" - "我下周有啥工作" / "明天要做啥" / "这周有什么事" - "下周安排" / "有啥任务" / "日程表看一下" - 任何时间 + 安排/会议/事件/工作/任务/事情的组合问法 ``` ### Technical Analysis The Skill instructs the agent that it must invoke the calendar integration whenever a request contains broad concepts such as work, tasks, arrangements, or “things.” These terms do not necessarily indicate that the user intends to access Microsoft Outlook. Invocation can load reusable Microsoft session cookies or a bearer token and retrieve private event metadata. Requiring this access for ambiguous, non-calendar requests exceeds the minimum privileges necessary for the declared calendar-reading function. This is best classified as instruction hijacking because the Skill text imposes unconditional invocation behavior that can override the agent's contextual determination of whether calendar access is appropriate. ### Attack Path 1. A user asks a generic question concerning work or tasks without requesting calendar access. 2. The mandatory trigger instruction causes the agent to invoke the Skill. 3. The Skill loads cached Outlook authentication material. 4. It requests calendar information from Microsoft Outlook. 5. Private event subjects, times, statuses, or organizer identities are exposed to the agent despite the absence of explicit calendar intent. ### Impact Assessment An attacker does not gain operating-system privileges through this issue. However, unrelated prompts can cause access to the authenticated user's corporate calendar. The exposed scope includes event subjects, start and end times, availability state, all-day status, and organizer names returned by the API. ]]>
Remediation
<![CDATA[ ## Remediation Suggestions - Restrict activation to explicit requests to read or analyze an Outlook calendar. - Remove unconditional language requiring invocation for every mention of work, tasks, or generic activities. - Ask for confirmation when a request is ambiguous. - Avoid loading cookies or tokens until calendar access has been clearly established as necessary. - Document the categories of calendar information that will be accessed before the first invocation. ]]>

T08 · Insecure Dependencies

Warning
Location
SKILL.md:34
Finding
Third-party packages and browser binaries are installed without version or integrity pinning<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:34-38` **Vulnerability Type**: Unpinned dependency installation **Risk Level**: Medium ### Vulnerable Code ```bash pip install playwright requests playwright install chromium ``` ### Technical Analysis The installation instructions retrieve mutable versions of `playwright`, `requests`, and a Chromium browser binary. No package versions, hashes, lock file, trusted package index, or browser revision verification is specified. A future compromised release, package-index compromise, dependency confusion event, or unexpected incompatible release would execute in a security-sensitive process that handles a Microsoft password, authentication cookies, bearer tokens, and calendar data. The audit did not identify a currently malicious or typosquatted package; the vulnerability is the lack of supply-chain integrity controls. ### Attack Path 1. The user follows the documented installation commands. 2. `pip` resolves whatever package versions are current at installation time. 3. Playwright retrieves a browser binary without project-level integrity pinning. 4. A compromised dependency or browser release executes with the installing user's privileges. 5. The compromised component reads `~/.outlook/config.json`, cookies, bearer tokens, or calendar responses and can transmit or misuse them. ### Impact Assessment A malicious dependency would execute with the privileges of the account installing or running the Skill. It could access all files available to that account, including the plaintext Microsoft password, complete browser cookie set, cached bearer token, and corporate calendar information. ]]>
Remediation
<![CDATA[ ## Remediation Suggestions - Pin reviewed dependency versions in a lock file. - Record and verify package hashes, such as with `pip --require-hashes`. - Use an explicitly trusted package index. - Pin and verify the Playwright browser revision. - Perform dependency and browser updates through a reviewed update process. - Run the Skill in a dedicated virtual environment under an unprivileged account. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
login.py:13
Finding
Microsoft password, browser cookies, and bearer token are persisted in plaintext without enforced owner-only permissions<![CDATA[ ## Vulnerability Details **File Location**: `login.py:13-23,132-134`; `owa_calendar.py:14-19,99-102`; `SKILL.md:22-31` **Vulnerability Type**: Insecure credential and session-token storage **Risk Level**: High ### Vulnerable Code ```python OUTLOOK_DIR = Path.home() / ".outlook" with open(OUTLOOK_DIR / "config.json") as f: cfg = json.load(f) EMAIL = cfg["email"] PASSWORD = cfg["password"] COOKIE_FILE = OUTLOOK_DIR / "cookies.json" COOKIE_FILE.parent.mkdir(exist_ok=True) STATUS_FILE = OUTLOOK_DIR / "login_status.txt" CMD_FILE = OUTLOOK_DIR / "login_cmd.txt" ``` ```python # 保存 Cookie cookies = ctx.cookies() with open(COOKIE_FILE, "w") as f: json.dump(cookies, f, indent=2) ``` ```python COOKIE_FILE = OUTLOOK_DIR / "cookies.json" TOKEN_FILE = OUTLOOK_DIR / "token.json" TOKEN_TTL = 3600 # Token 复用 1 小时 ``` ```python TOKEN_FILE.parent.mkdir(exist_ok=True) with open(TOKEN_FILE, "w") as f: json.dump({"bearer": owa_token, "saved_at": time.time()}, f) ``` The documented configuration also stores the password directly: ```json { "email": "your@company.com", "password": "your_password", "cookie_file": "/root/.outlook/cookies.json", "cookie_max_age_days": 7, "mfa_type": "authenticator_number_match" } ``` ### Technical Analysis The Skill stores a Microsoft account password, all browser-context cookies, and an intercepted bearer token in plaintext files under `~/.outlook`. Neither the directory nor the files are explicitly assigned owner-only permissions. Their effective access control therefore depends on the user's existing umask and any pre-existing directory or file permissions. The complete cookie set may include session artifacts beyond those strictly necessary for calendar access. The bearer token is cached for one hour, while cookies may remain reusable for multiple days. The password remains stored indefinitely. The reviewed network destinations are Microsoft HTTPS endpoints only: `login.microsoftonline.com` and `outlook. ...[truncated 1262 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Create `~/.outlook` with mode `0700`. - Create configuration, cookie, token, status, and diagnostic files atomically with mode `0600`. - Validate permissions on existing files and refuse to use files readable by group or other users. - Store the password and reusable tokens in an operating-system credential manager rather than JSON. - Prefer an official Microsoft OAuth flow with narrowly scoped, revocable tokens instead of browser-request interception. - Save only the minimum cookies required for Outlook rather than the entire browser cookie set. - Remove expired token files immediately and provide a command to revoke and delete all local authentication artifacts. - Avoid retaining the account password after an authenticated session has been established. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
login.py:19
Finding
Authentication-page screenshots and status information are retained without secure permissions or cleanup<![CDATA[ ## Vulnerability Details **File Location**: `login.py:19-38,86-92,115-117` **Vulnerability Type**: Insecure diagnostic artifact storage **Risk Level**: Medium ### Vulnerable Code ```python STATUS_FILE = OUTLOOK_DIR / "login_status.txt" CMD_FILE = OUTLOOK_DIR / "login_cmd.txt" def log(msg): print(msg, flush=True) with open(STATUS_FILE, "a") as f: f.write(f"{msg}\n") def shot(page, name): try: path = OUTLOOK_DIR / f"debug_{name}.png" page.screenshot(path=str(path)) except: pass ``` ```python for i in range(20): time.sleep(2) n = find_number(page) if n: log(f"[2] 屏幕数字: 【{n}】") log(f"[NUMBER:{n}]") break shot(page, f"wait_{i:02d}") ``` ```python if i % 10 == 0: shot(page, f"poll_{i:02d}") log(f"[3/{i*2}s] 等待中...") ``` ### Technical Analysis The login process repeatedly captures screenshots of the live Microsoft authentication page while waiting for MFA. It also writes MFA matching numbers and redirect URLs to a persistent status file. These files have no explicit owner-only mode, retention limit, or automatic cleanup. Authentication pages can contain account identifiers, tenant branding, MFA challenge details, error messages, and redirect information. Although an MFA matching number alone is short-lived and insufficient to authenticate independently, retaining it with screenshots and login context increases local information exposure and can support targeted phishing or session reconnaissance. ### Attack Path 1. A login is delayed or encounters an MFA-related error. 2. The polling loops generate authentication-page screenshots. 3. The script records the MFA matching value and login progress in `login_status.txt`. 4. The files remain under `~/.outlook` after authentication completes. 5. A local attacker or backup process obtains the retained files and extracts account or tenant context useful for reconnaissance or social engineering. ### Impact As ...[truncated 366 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Disable authentication screenshots by default and require an explicit diagnostic flag. - Do not log MFA matching numbers. - Redact query parameters, tenant identifiers, and other sensitive components before logging URLs. - Create diagnostic files with mode `0600`. - Automatically remove screenshots and status files after successful login. - Apply a short retention period and bounded file count when diagnostic mode is enabled. - Replace broad exception suppression with controlled error handling that does not require persistent page captures. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
login.py:66
Finding
Chromium sandbox is disabled during credentialed Microsoft sessions<![CDATA[ ## Vulnerability Details **File Location**: `login.py:66-69`; `owa_calendar.py:70` **Vulnerability Type**: Unsafe browser security configuration **Risk Level**: Medium ### Vulnerable Code ```python browser = p.chromium.launch( headless=True, args=["--no-sandbox", "--disable-dev-shm-usage"] ) ``` ```python browser = p.chromium.launch(headless=True, args=["--no-sandbox", "--disable-dev-shm-usage"]) ``` ### Technical Analysis Both scripts launch Chromium with `--no-sandbox`. The browser processes handle the Microsoft password, session cookies, bearer token, and authenticated Outlook pages. Disabling Chromium's sandbox removes a major defense-in-depth boundary intended to contain renderer compromise. The audited code loads only Microsoft HTTPS pages and does not intentionally visit attacker-controlled domains. Exploitation therefore requires compromised upstream content, malicious third-party content loaded by the page, DNS/TLS compromise, or a browser vulnerability reachable through Microsoft-hosted content. Despite that prerequisite, disabling the sandbox unnecessarily increases the consequences of a browser exploit and is not normally required for an unprivileged desktop process. ### Attack Path 1. The Skill launches Chromium with its sandbox disabled. 2. Chromium loads Microsoft authentication or Outlook web content. 3. Malicious or compromised web content exploits a browser vulnerability. 4. Because the sandbox is disabled, the compromised renderer has reduced process isolation. 5. The attacker accesses files available to the invoking user, including `~/.outlook` credentials, cookies, tokens, and other user data. ### Impact Assessment Successful browser exploitation could obtain the privileges of the user running the Skill rather than remaining contained in a renderer sandbox. The accessible scope can include Microsoft authentication artifacts and any other files readable or writable by that operating-system account. ]]>
Remediation
<![CDATA[ ## Remediation Suggestions - Remove the `--no-sandbox` Chromium argument. - Run the Skill as a dedicated, unprivileged operating-system user. - If the environment cannot support Chromium's sandbox, execute the browser in a hardened container or virtual machine with no unrelated secrets. - Use a read-only filesystem where practical and mount only the minimum authentication storage required. - Keep Chromium and Playwright pinned to reviewed, security-supported versions. - Apply network egress restrictions allowing only the required Microsoft domains. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (18)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The skill behavior includes obtaining/intercepting authentication material and caching Bearer tokens locally, which is materially more sensitive than simply answering calendar questions. In the context of an enterprise Outlook skill, undisclosed token and cookie handling is especially dangerous because those artifacts may grant access to mailbox and calendar data beyond the immediate request.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The skill behavior includes obtaining/intercepting authentication material and caching Bearer tokens locally, which is materially more sensitive than simply answering calendar questions. In the context of an enterprise Outlook skill, undisclosed token and cookie handling is especially dangerous because those artifacts may grant access to mailbox and calendar data beyond the immediate request.

Vague Triggers

High
Confidence
97% confidence
Finding
The trigger rule says the skill must be invoked for essentially any question involving plans, work, tasks, or events, which overlaps heavily with ordinary conversation and non-calendar requests. Overbroad mandatory triggering can cause unnecessary access to sensitive enterprise calendar data and surprise users by routing benign prompts into a privileged skill.

Vague Triggers

High
Confidence
98% confidence
Finding
The instruction mandates invocation for ambiguous categories like '工作', '任务', and '事情' without requiring clear user intent to access Outlook. In this context, that increases privacy risk because an enterprise-integrated skill may activate on broad productivity questions and expose or process calendar data when no account access was intended.

Description-Behavior Mismatch

High
Confidence
97% confidence
Finding
Although the skill is presented as a calendar-reading integration, the code performs full browser-based account login automation, handles MFA interaction, clicks 'stay signed in,' and then saves the resulting session. That materially expands capability from narrow calendar access to durable account access, which is especially dangerous in an enterprise Microsoft 365 context.

Context-Inappropriate Capability

High
Confidence
98% confidence
Finding
The script exports and persists Microsoft 365/Outlook session cookies to disk after login, effectively creating reusable authenticated session material outside the browser's managed protections. If those cookies are copied or exposed, an attacker may be able to hijack the user's Microsoft 365 session and access more than just calendar data depending on the session scope.

Context-Inappropriate Capability

High
Confidence
99% confidence
Finding
The request hook inspects outbound browser traffic and extracts Authorization headers, which is a sensitive interception capability unrelated to a simple calendar-query implementation. This creates a credential-capture primitive that could be reused to obtain tokens for other resources or sessions, especially because it keys off browser traffic rather than a constrained authentication API.

Missing User Warnings

High
Confidence
98% confidence
Finding
The skill derives authentication from stored cookies and silently captures the resulting Bearer token from network requests, which bypasses normal user expectations for authentication handling. In the context of an enterprise Microsoft 365 calendar skill, this is especially dangerous because it can turn an ordinary read helper into a hidden token-extraction mechanism against corporate data.

Lp3

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding
The skill declares no explicit tool restrictions even though it instructs the agent to perform network access and local file writes for credential, cookie, and token handling. In an agent environment, missing scope boundaries increases the chance of unintended credential access, persistence, or outbound requests beyond what users expect from a calendar-reading skill.

Natural-Language Policy Violations

Medium
Confidence
94% confidence
Finding
Forcing UTC+8/Shanghai time without checking the user or mailbox timezone can produce incorrect scheduling answers, missed meetings, or inaccurate hour totals. In a calendar skill, timezone correctness is safety-relevant because users may rely on the output for real-world attendance and planning.

Context-Inappropriate Capability

Medium
Confidence
94% confidence
Finding
The script reads a Microsoft 365 email address and password from a local config file, introducing direct handling of primary account credentials. For a skill whose declared purpose is only reading Outlook calendar data, collecting and using reusable credentials is broader than necessary and increases the chance of credential theft, accidental disclosure, or reuse beyond the intended scope.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
Reading credentials from a local file without clear disclosure or secure handling is a sensitive-data practice issue that can expose users to silent collection and misuse of account secrets. In this context, the absence of user-facing warning is more concerning because the skill description implies a simple calendar reader, not a password-consuming login helper.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
Writing authentication cookies to disk without explicit warning creates persistent sensitive session storage that users may not realize exists. Those files can be stolen by local malware, other users on the system, or backups/log collection, enabling session replay or unauthorized account access.

Natural-Language Policy Violations

Medium
Confidence
88% confidence
Finding
The script's natural-language descriptions and user-facing messages are written in Chinese, and output formatting also assumes Chinese-language presentation. The file does not offer any language or locale choice, nor does it document a region-specific justification for enforcing this locale.

Context-Inappropriate Capability

Medium
Confidence
95% confidence
Finding
The code loads and reuses a cached Bearer token from a local file for up to an hour, extending the useful lifetime of a sensitive credential beyond the interactive session. If another local process, user, or backup/logging mechanism can read that file, the token may be replayed to access calendar data or other permitted resources.

Description-Behavior Mismatch

Medium
Confidence
97% confidence
Finding
The skill’s stated purpose is narrow read-only calendar retrieval, but the implementation goes beyond that by harvesting a Bearer token from live browser traffic and persisting it for later reuse. A reusable access token can often be used outside the immediate script context to access the user’s Microsoft 365 data, creating credential theft and lateral misuse risk if the file is exposed or the skill is repurposed.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
Writing the intercepted Bearer token to disk without explicit disclosure or consent creates a stealth credential-retention risk. Users may believe the skill only reads calendar entries, while in reality it leaves behind a reusable authentication artifact that could be stolen or reused later.

Natural-Language Policy Violations

Low
Confidence
93% confidence
Finding
User-facing strings in the module description and runtime logs are written only in Chinese. Under the stated policy, forcing a specific language without opt-in can be a natural-language policy violation unless the locale limitation is explicitly justified.

Static analysis

No suspicious patterns detected.