Back to skill

Security audit

ics to exchange-blocker

Security checks for vulnerabilities and agentic risk

Overview

This skill is a disclosed calendar-sync tool, but it handles calendar credentials, Microsoft calendar write access, and optional background syncing, so users should install it deliberately.

Install only if you are comfortable granting Microsoft Calendars.ReadWrite permission and storing a secret ICS URL plus Microsoft tokens under ~/.calintegration. Keep the .env and token files private, consider pinning dependencies before installing, and only load the LaunchAgent if you want the sync to run automatically every 5 minutes.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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)

T08 · Insecure Dependencies

Warning
Location
requirements.txt:1
Finding

Unpinned and Unverified Third-Party Dependencies

Content
View full analysis
=5.0.0 msal>=1.20.0 recurring-ical-events>=3.0.0 requests>=2.28.0 ``` The installer directly installs these dependencies: ```bash "$VENV_DIR/bin/pip" install -q -r "$SCRIPT_DIR/requirements.txt" ``` ### Technical Analysis Every dependency uses an open-ended minimum-version constraint. No upper bounds, exact versions, package hashes, lock file, or explicit trusted package index are specified. Consequently, the effective code installed by the Skill can change after the Skill itself has been reviewed. The use of legitimate package names means this is not evidence of an intentionally malicious package or current compromise. Nevertheless, a compromised future release, compromised transitive dependency, or malicious response from an untrusted pip index could introduce arbitrary code into the environment. Python packages can execute code during installation and whenever imported. These dependencies are subsequently imported by the calendar synchronization process, so compromised runtime modules would also execute during normal and scheduled synchronization. ### Attack Path 1. An attacker compromises a compatible future release of one of the listed packages, one of its transitive dependencies, or a pip index trusted by the user. 2. The user runs `install.sh`. 3. pip resolves the mutable `>=` constraints to the attacker-controlled release. 4. Malicious package code executes during installation or when the Skill imports the dependency. 5. The malicious code runs with the privileges of the user who installed or invoked the Skill. 6. It may access `~/.calintegration/.env`, `~/.calintegration/ms_token.json`, the secret ICS feed URL, local files readable by the user, and the network. ### Impact Assessment Successful exploitation provides code execution ...[truncated 419 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
ics_source.py:12
Finding

Incomplete ICS URL Validation Permits Redirect-Based SSRF

Content
View full analysis
str: parsed = urlparse(url) if parsed.scheme != "https": raise ValueError(f"ICS URL must use HTTPS, got: {parsed.scheme}") return url ``` ```python url = _validate_ics_url(config.ICS_URL) resp = requests.get(url, timeout=30, verify=True) resp.raise_for_status() ``` ### Technical Analysis The validation only verifies that the initially configured URL has an `https` scheme. It does not validate the destination hostname or resolved IP address, and it does not reject loopback, private, link-local, reserved, or cloud metadata addresses. In addition, `requests.get()` follows redirects by default. Redirect destinations are not passed through `_validate_ics_url()`. An initially valid HTTPS calendar URL can therefore redirect the client to an internal host or another disallowed destination, including a non-HTTPS URL. TLS certificate verification and a request timeout are enabled, which reduce interception and denial-of-service risks, but they do not prevent SSRF. The documentation's claim that rejecting non-HTTPS initial URLs prevents SSRF is therefore stronger than the implementation supports. ### Attack Path 1. A user configures an attacker-controlled or compromised HTTPS ICS endpoint as `CALINT_ICS_URL`. 2. The Skill validates only the initial `https` scheme. 3. The endpoint returns an HTTP redirect to a loopback, private-network, link-local, metadata, or otherwise sensitive service. 4. `requests` automatically follows the redirect. 5. The Skill sends a GET request from the user's machine to the destination. 6. If the response is successful and within the size limit, it is read and passed to the ICS parser. A similar path may be possible without a redirect if a permitte ...[truncated 726 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Note
Location
install.sh:22
Finding

Installer Does Not Repair Permissions on Existing Credential Paths

Content
View full analysis
> "$ENV_FILE" <<'ENVEOF' # CalIn credentials — keep this file chmod 600 # CALINT_ICS_URL= # CALINT_MS_CLIENT_ID= # CALINT_MS_TENANT_ID= ENVEOF echo "Created $ENV_FILE (chmod 600) — edit it with your credentials" else echo "$ENV_FILE already exists" fi ``` ### Technical Analysis `mkdir -m 700 -p` applies the requested mode when creating a directory, but it does not change the mode of an existing directory. Likewise, the installer applies mode `0600` only when it creates a new `.env` file. If either path already exists with permissive access, installation reports success without correcting the permissions. This contradicts the documented assurance that the credential directory and file use modes `0700` and `0600`. The code also does not verify path ownership or reject symbolic links before trusting the existing paths. The Microsoft client and tenant IDs are not normally confidential on their own, but `CALINT_ICS_URL` may contain a bearer-like secret token that grants read access to a private calendar. ### Attack Path 1. `~/.calintegration` or its `.env` file already exists with group-readable or world-readable permissions. 2. The user runs `install.sh`. 3. The installer leaves the existing permissions unchanged. 4. The user adds the secret ICS feed URL and Microsoft configuration to `.env`. 5. Another local account with applicable filesystem access reads the file. 6. The exposed ICS URL may then be used to retrieve private calendar data directly from the calendar provider. If pre-existing paths a ...[truncated 688 chars]
Remediation
View remediation
"$ENV_FILE" fi chmod 600 "$ENV_FILE" ``` 2. Quote all path references consistently. 3. Verify that the directory and file are owned by the current user. 4. Use `lstat`-equivalent checks to reject symbolic links for the data directory and credential file. 5. Set a restrictive `umask`, such as `umask 077`, near the beginning of the installer. 6. Fail securely when ownership or permission correction is unsuccessful. 7. Apply equivalent ownership and mode checks to the Microsoft token cache and synchronization state files. ]]>
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
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (42)

Credential Access

High
Category
Privilege Escalation
Confidence
88% confidence
Finding

The skill explicitly depends on a local .env file containing a secret ICS URL and Microsoft identifiers, which means it handles sensitive credentials and tokens. In agent ecosystems, undeclared or overly broad credential access can expose secrets to the skill runtime or to other components if file boundaries are not tightly enforced.

Content

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

md
bins:
        - python3
      config:
        - ~/.calintegration/.env
    primaryEnv: CALINT_ICS_URL
    files: ["*.py", "install.sh", "requirements.txt"]
  homepage: https://github.com/Blucaru/CalIn

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 · config.py (reported line 15)May include surrounding context.

python
DATA_DIR = Path.home() / ".calintegration"
DATA_DIR.mkdir(mode=0o700, exist_ok=True)

# Load .env file if present
_env_file = DATA_DIR / ".env"
if _env_file.exists():
    for line in _env_file.read_text().splitlines():

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 · install.sh (reported line 25)May include surrounding context.

sh
DATA_DIR = Path.home() / ".calintegration"
DATA_DIR.mkdir(mode=0o700, exist_ok=True)

# Load .env file if present
_env_file = DATA_DIR / ".env"
if _env_file.exists():
    for line in _env_file.read_text().splitlines():

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 · config.py (reported line 16)May include surrounding context.

python
DATA_DIR.mkdir(mode=0o700, exist_ok=True)

# Load .env file if present
_env_file = DATA_DIR / ".env"
if _env_file.exists():
    for line in _env_file.read_text().splitlines():
        line = line.strip()

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 · install.sh (reported line 26)May include surrounding context.

sh
DATA_DIR.mkdir(mode=0o700, exist_ok=True)

# Load .env file if present
_env_file = DATA_DIR / ".env"
if _env_file.exists():
    for line in _env_file.read_text().splitlines():
        line = line.strip()

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 · ms_auth.py (reported line 80)May include surrounding context.

python
def get_access_token() -> str:
    """Get a valid access token, using cached tokens or interactive login."""
    app = _get_msal_app()

    # Try cached accounts first

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding

The skill advertises significant capabilities—reading environment/config, reading and writing local files, making network calls, and invoking shell commands—but does not declare any explicit tool scope or permissions boundary. That increases the chance of over-broad execution in agent environments because consumers cannot easily understand or constrain what the skill is allowed to access.

Content

No source excerpt is available for this finding.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

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

2. Configure credentials

Add to ~/.calintegration/.env (created by installer with chmod 600):

text
CALINT_ICS_URL=<your-ics-feed-url>

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

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.

Content

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

md
**Azure AD app** (free, no client secret needed):
1. Go to https://portal.azure.com/#view/Microsoft_AAD_RegisteredApps/ApplicationsListBlade
2. New registration > Name: "CalIn" > Redirect URI: Public client > `http://localhost:8400`
3. API permissions > Add > Microsoft Graph > Delegated > Calendars.ReadWrite
4. Copy Application (client) ID and Directory (tenant) ID

### 3. Authenticate Microsoft

Session Persistence

Medium
Category
Rogue Agent
Confidence
93% confidence
Finding

The skill instructs users to install a launchd plist for recurring execution every 5 minutes, which establishes persistence on the host. Even though the purpose is functional automation, persistence materially increases risk because a compromised or modified skill would continue running and making network/API calls without repeated user initiation.

Content

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

Automated Sync (macOS)

The installer generates a launchd plist for automatic sync every 5 minutes:

bash
cd ~/.openclaw/skills/calin

Session Persistence

Medium
Category
Rogue Agent
Confidence
94% confidence
Finding

Copying a plist into ~/Library/LaunchAgents installs a user-level persistence mechanism that will survive across sessions and restarts. In the context of a networked skill with credential access, this increases the blast radius of any future bug, compromise, or malicious update.

Content

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

bash
cd ~/.openclaw/skills/calin
bash install.sh
cp com.calintegration.sync.plist ~/Library/LaunchAgents/
launchctl load ~/Library/LaunchAgents/com.calintegration.sync.plist

Session Persistence

Medium
Category
Rogue Agent
Confidence
90% confidence
Finding

This duplicate plist-related finding points to the same persistence behavior: a LaunchAgent is being activated for recurring background execution. Persistence is not inherently malicious here, but it is security-relevant and should be treated as a real risk factor because it enables ongoing access and activity without foreground user interaction.

Content

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

cd ~/.openclaw/skills/calin bash install.sh cp com.calintegration.sync.plist ~/Library/LaunchAgents/ launchctl load ~/Library/LaunchAgents/com.calintegration.sync.plist

text

## How It Works

Session Persistence

Medium
Category
Rogue Agent
Confidence
90% confidence
Finding

This duplicate plist-related finding points to the same persistence behavior: a LaunchAgent is being activated for recurring background execution. Persistence is not inherently malicious here, but it is security-relevant and should be treated as a real risk factor because it enables ongoing access and activity without foreground user interaction.

Content

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

cd ~/.openclaw/skills/calin bash install.sh cp com.calintegration.sync.plist ~/Library/LaunchAgents/ launchctl load ~/Library/LaunchAgents/com.calintegration.sync.plist

text

## How It Works

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

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

md
- **Credentials** stored in `~/.calintegration/.env` with chmod 600 permissions
- **Tokens** stored in `~/.calintegration/ms_token.json` with chmod 600 permissions
- **All files** in `~/.calintegration/` directory with chmod 700
- **No event details synced** — only time slots are transmitted. Event titles, descriptions, attendees, and locations are never sent to Exchange
- **HTTPS only** — ICS URLs must use HTTPS; Graph API calls use TLS with certificate verification
- **No client secret** — uses PKCE (Proof Key for Code Exchange) for Microsoft auth

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
83% confidence
Finding

The function performs an HTTP GET to a user-provided calendar URL, which transmits calendar access information to a remote service and retrieves potentially sensitive event data. While the code validates HTTPS and prints setup guidance, it does not disclose that the skill will contact the remote calendar provider and access calendar contents.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

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.

Content

Scanner excerpt · install.sh (reported line 10)May include surrounding context.

sh
echo "=== CalIn Installer ==="
echo

# Create virtualenv
if [ ! -d "$VENV_DIR" ]; then
    echo "Creating virtual environment..."
    python3 -m venv "$VENV_DIR"

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

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

md
ENV_FILE="$HOME/.calintegration/.env"
if [ ! -f "$ENV_FILE" ]; then
    touch "$ENV_FILE"
    chmod 600 "$ENV_FILE"
    cat >> "$ENV_FILE" <<'ENVEOF'
# CalIn credentials — keep this file chmod 600
# CALINT_ICS_URL=

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

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

md
ENV_FILE="$HOME/.calintegration/.env"
if [ ! -f "$ENV_FILE" ]; then
    touch "$ENV_FILE"
    chmod 600 "$ENV_FILE"
    cat >> "$ENV_FILE" <<'ENVEOF'
# CalIn credentials — keep this file chmod 600
# CALINT_ICS_URL=

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · install.sh (reported line 29)May include surrounding context.

sh
ENV_FILE="$HOME/.calintegration/.env"
if [ ! -f "$ENV_FILE" ]; then
    touch "$ENV_FILE"
    chmod 600 "$ENV_FILE"
    cat >> "$ENV_FILE" <<'ENVEOF'
# CalIn credentials — keep this file chmod 600
# CALINT_ICS_URL=

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · install.sh (reported line 31)May include surrounding context.

sh
ENV_FILE="$HOME/.calintegration/.env"
if [ ! -f "$ENV_FILE" ]; then
    touch "$ENV_FILE"
    chmod 600 "$ENV_FILE"
    cat >> "$ENV_FILE" <<'ENVEOF'
# CalIn credentials — keep this file chmod 600
# CALINT_ICS_URL=

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · install.sh (reported line 36)May include surrounding context.

sh
ENV_FILE="$HOME/.calintegration/.env"
if [ ! -f "$ENV_FILE" ]; then
    touch "$ENV_FILE"
    chmod 600 "$ENV_FILE"
    cat >> "$ENV_FILE" <<'ENVEOF'
# CalIn credentials — keep this file chmod 600
# CALINT_ICS_URL=

Session Persistence

Medium
Category
Rogue Agent
Confidence
83% confidence
Finding

The script generates a launchd plist that configures periodic execution of the sync program every 5 minutes and at load. While presented as an optional convenience feature, this is persistence behavior and can expand risk if the synced application or its dependencies are later compromised, because the agent will keep re-executing automatically.

Content

Scanner excerpt · install.sh (reported line 41)May include surrounding context.

sh
echo "$ENV_FILE already exists"
fi

# Generate launchd plist with correct paths for this machine
PLIST_FILE="$SCRIPT_DIR/com.calintegration.sync.plist"
cat > "$PLIST_FILE" <<PLISTEOF
<?xml version="1.0" encoding="UTF-8"?>

Session Persistence

Medium
Category
Rogue Agent
Confidence
83% confidence
Finding

The same line is correctly associated with persistence because it initiates writing a plist file for launchd. The danger is contextual rather than overtly malicious: a periodic background task increases the blast radius of any future compromise of main.py, the virtualenv, or installed packages.

Content

Scanner excerpt · install.sh (reported line 42)May include surrounding context.

sh
fi

# Generate launchd plist with correct paths for this machine
PLIST_FILE="$SCRIPT_DIR/com.calintegration.sync.plist"
cat > "$PLIST_FILE" <<PLISTEOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">

Session Persistence

Medium
Category
Rogue Agent
Confidence
83% confidence
Finding

The same line is correctly associated with persistence because it initiates writing a plist file for launchd. The danger is contextual rather than overtly malicious: a periodic background task increases the blast radius of any future compromise of main.py, the virtualenv, or installed packages.

Content

Scanner excerpt · install.sh (reported line 42)May include surrounding context.

sh
fi

# Generate launchd plist with correct paths for this machine
PLIST_FILE="$SCRIPT_DIR/com.calintegration.sync.plist"
cat > "$PLIST_FILE" <<PLISTEOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">

Session Persistence

Medium
Category
Rogue Agent
Confidence
82% confidence
Finding

Embedding a full launchd plist definition indicates planned persistence on macOS. Although the stated purpose is recurring calendar sync, autorun code should be treated carefully because it provides a durable execution path if anything in the run chain is replaced or poisoned.

Content

Scanner excerpt · install.sh (reported line 43)May include surrounding context.

sh
# Generate launchd plist with correct paths for this machine
PLIST_FILE="$SCRIPT_DIR/com.calintegration.sync.plist"
cat > "$PLIST_FILE" <<PLISTEOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">

Static analysis

No suspicious patterns detected.