T05 · Unauthorized Access and Privilege Escalation
- Location
scripts/setup-device-code.sh:109- Finding
Unnecessary User.Read Permission and Profile Data Retrieval
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This skill is a disclosed Microsoft To Do integration with persistent Microsoft Graph tokens and guarded task writes, with some low-risk over-permission and unused helper-code residue to review.
Install only if you are comfortable granting this skill ongoing delegated access to read and modify your Microsoft To Do tasks. Treat ~/.outlook-todo as sensitive because it stores refresh tokens, use token.sh clear when done, and consider reducing User.Read in a future version if profile validation is not needed.
scripts/setup-device-code.sh:109Unnecessary User.Read Permission and Profile Data Retrieval
If the advertised write functionality, dedicated device-code auth flow, and confirmation safeguards are absent from the real code, users and orchestration systems may make incorrect trust decisions about what the skill can and cannot do. While this second mismatch report appears partly inconsistent with the markdown itself and may reflect scanner confusion across code chunks, any real divergence between documented safety controls and implemented behavior is security-relevant because it defeats informed approval.
If the advertised write functionality, dedicated device-code auth flow, and confirmation safeguards are absent from the real code, users and orchestration systems may make incorrect trust decisions about what the skill can and cannot do. While this second mismatch report appears partly inconsistent with the markdown itself and may reflect scanner confusion across code chunks, any real divergence between documented safety controls and implemented behavior is security-relevant because it defeats informed approval.
Referenced artifact was not completely inspected
| `SKILL.md` | this file |
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
#!/usr/bin/env bash
# scripts/token.sh
# Inspect or refresh the Microsoft Graph access token used by outlook-todo.
#
# Subcommands:
# status Show token presence & expiry (no token value ever printed).
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
#!/usr/bin/env bash
# scripts/token.sh
# Inspect or refresh the Microsoft Graph access token used by outlook-todo.
#
# Subcommands:
# status Show token presence & expiry (no token value ever printed).
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
#!/usr/bin/env bash
# scripts/token.sh
# Inspect or refresh the Microsoft Graph access token used by outlook-todo.
#
# Subcommands:
# status Show token presence & expiry (no token value ever printed).
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
#!/usr/bin/env bash
# scripts/token.sh
# Inspect or refresh the Microsoft Graph access token used by outlook-todo.
#
# Subcommands:
# status Show token presence & expiry (no token value ever printed).
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
#!/usr/bin/env bash
# scripts/token.sh
# Inspect or refresh the Microsoft Graph access token used by outlook-todo.
#
# Subcommands:
# status Show token presence & expiry (no token value ever printed).
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
#!/usr/bin/env bash
# scripts/token.sh
# Inspect or refresh the Microsoft Graph access token used by outlook-todo.
#
# Subcommands:
# status Show token presence & expiry (no token value ever printed).
Without declared permissions the skill's intent is opaque and cannot be validated.
The skill explicitly stores access and refresh tokens under ~/.outlook-todo/, creating persistent delegated Graph access beyond a single session. Persistent tokens increase risk if the host, user account, backups, or local files are compromised, especially because offline_access enables token renewal without re-prompting the user.
name: outlook-todo
license: MIT
description: |
Read and write Microsoft To Do via its own Microsoft Graph device-code login.
Enumerate task lists, read/filter tasks, and create, update, complete, or delete tasks
(writes require --apply plus a typed-YES prompt or an explicit --yes flag).
metadata:
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.
Formats: `summary`, `json`, `ids`, `raw`.
## Write tasks (explicit confirmation required)
`todo-write.sh` supports **create / update / complete / delete**. Every write defaults to
**dry-run** (prints the JSON payload; may perform read-only Graph lookups such as
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
}
_lib__require_bin jq
_lib__require_bin curl
# python3 is preferred for some pretty-printer paths; warn if missing
if ! command -v python3 >/dev/null 2>&1; then
echo "outlook-todo: warning: python3 not found, table formatting will fall back to jq" >&2
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.
if [[ ! -d "$OUTLOOK_TODO_DIR" ]]; then
mkdir -p "$OUTLOOK_TODO_DIR" || die "cannot create $OUTLOOK_TODO_DIR"
fi
# chmod 700; a failure here means tokens would sit on a permissive location
if ! chmod 700 "$OUTLOOK_TODO_DIR" 2>/dev/null; then
die "could not chmod 700 $OUTLOOK_TODO_DIR; refusing to store tokens in a permissive location"
fi
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.
if [[ ! -d "$OUTLOOK_TODO_DIR" ]]; then
mkdir -p "$OUTLOOK_TODO_DIR" || die "cannot create $OUTLOOK_TODO_DIR"
fi
# chmod 700; a failure here means tokens would sit on a permissive location
if ! chmod 700 "$OUTLOOK_TODO_DIR" 2>/dev/null; then
die "could not chmod 700 $OUTLOOK_TODO_DIR; refusing to store tokens in a permissive location"
fi
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.
if [[ ! -d "$OUTLOOK_TODO_DIR" ]]; then
mkdir -p "$OUTLOOK_TODO_DIR" || die "cannot create $OUTLOOK_TODO_DIR"
fi
# chmod 700; a failure here means tokens would sit on a permissive location
if ! chmod 700 "$OUTLOOK_TODO_DIR" 2>/dev/null; then
die "could not chmod 700 $OUTLOOK_TODO_DIR; refusing to store tokens in a permissive location"
fi
The natural-language comments and implementation set Asia/Shanghai as the default timezone and present it as the standard usage, which imposes a specific locale on users without offering a choice or explaining why this locale is required. This matches the policy category for language/locale constraints applied without user opt-in.
The manifest describes a skill for reading and writing Microsoft To Do tasks and task lists, but this helper file contains event-specific functionality such as building calendar event request bodies and printing event summaries. Calendar event handling is a separate Graph domain from To Do tasks, so this behavior exceeds the described feature set rather than serving as an obvious implementation detail of task management.
The function documentation and code state that the event timezone defaults to Asia/Shanghai, which creates locale-specific behavior for all users unless they override it. There is no nearby justification that the skill is China-specific or any opt-in mechanism for this locale choice.
The script intentionally requests offline_access and persists refresh/access tokens to disk, creating durable session material that can be reused if the local host or home directory is compromised. In the context of a To Do integration this is expected functionality, but the stored tokens still grant ongoing Microsoft Graph access and therefore represent a meaningful credential-theft target.
# 2. Requests exactly the minimal To Do consent set (documented in SKILL.md):
# offline_access
# https://graph.microsoft.com/User.Read
# https://graph.microsoft.com/Tasks.ReadWrite
# No shared family token store, no calendar or contacts scopes, no mail,
# no files, no directory scopes — ever.
# 3. Calls the /devicecode endpoint and prints a short user code + verification URL.
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.
# - The device_code and verification_uri are NOT secrets (they are short-lived and
# require the user's own credentials to redeem). They are echoed to stderr so
# they appear in the terminal but are not logged to any file.
# - The access_token and refresh_token are written only to tokens.json (chmod 600)
# and NEVER echoed to stdout/stderr. The only thing printed about the token is
# its expiry timestamp.
# - No mail scopes are ever requested. The /me probe uses User.Read only.
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.
# - The device_code and verification_uri are NOT secrets (they are short-lived and
# require the user's own credentials to redeem). They are echoed to stderr so
# they appear in the terminal but are not logged to any file.
# - The access_token and refresh_token are written only to tokens.json (chmod 600)
# and NEVER echoed to stdout/stderr. The only thing printed about the token is
# its expiry timestamp.
# - No mail scopes are ever requested. The /me probe uses User.Read only.
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.
# - The device_code and verification_uri are NOT secrets (they are short-lived and
# require the user's own credentials to redeem). They are echoed to stderr so
# they appear in the terminal but are not logged to any file.
# - The access_token and refresh_token are written only to tokens.json (chmod 600)
# and NEVER echoed to stdout/stderr. The only thing printed about the token is
# its expiry timestamp.
# - No mail scopes are ever requested. The /me probe uses User.Read only.
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.
# - The device_code and verification_uri are NOT secrets (they are short-lived and
# require the user's own credentials to redeem). They are echoed to stderr so
# they appear in the terminal but are not logged to any file.
# - The access_token and refresh_token are written only to tokens.json (chmod 600)
# and NEVER echoed to stdout/stderr. The only thing printed about the token is
# its expiry timestamp.
# - No mail scopes are ever requested. The /me probe uses User.Read only.
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.
# - The device_code and verification_uri are NOT secrets (they are short-lived and
# require the user's own credentials to redeem). They are echoed to stderr so
# they appear in the terminal but are not logged to any file.
# - The access_token and refresh_token are written only to tokens.json (chmod 600)
# and NEVER echoed to stdout/stderr. The only thing printed about the token is
# its expiry timestamp.
# - No mail scopes are ever requested. The /me probe uses User.Read only.
No suspicious patterns detected.