Back to skill

Security audit

Caldav

Security checks for vulnerabilities and agentic risk

Overview

This appears to be a real CalDAV/Radicale management skill, but it needs review because it handles credentials and calendar data and includes privileged server-administration steps without enough safeguards.

Install only if you are comfortable giving an agent access to your CalDAV account and, for Radicale workflows, local server administration. Prefer HTTPS except for loopback testing, avoid storing passwords in plaintext config, do not paste real passwords into curl commands, review delete/update commands before running them, and treat systemctl enable/start or htpasswd user changes as explicit administrator actions.

Vulnerability Patterns
  • System PersistenceInstalls backdoors, hooks, services, or scheduled tasks that survive the run
  • 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
Findings (5)

T06 · System Persistence

Error
Location
SKILL.md:263
Finding

Privileged Radicale Service Persistence

Content
View full analysis
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
SKILL.md:34
Finding

Unpinned CalDAV and iCalendar Dependencies

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/utils.py:18
Finding

CalDAV Credentials Can Be Sent over Plaintext HTTP

Content
View full analysis
Dict[str, Any]: """Load configuration from file or environment.""" config = {} # Try config files for config_path in CONFIG_PATHS: if config_path.exists(): with open(config_path) as f: config.update(json.load(f)) break # Environment overrides if os.environ.get("CALDAV_URL"): config["url"] = os.environ["CALDAV_URL"] if os.environ.get("CALDAV_USER"): config["username"] = os.environ["CALDAV_USER"] if os.environ.get("CALDAV_PASSWORD"): config["password"] = os.environ["CALDAV_PASSWORD"] return config def get_client(): """Get authenticated CalDAV client.""" try: from caldav import DAVClient except ImportError: print("Error: caldav library not installed.") print("Install with: pip install caldav") raise SystemExit(1) config = load_config() if not config.get("url"): print("Error: No CalDAV URL configured.") print("Set CALDAV_URL environment variable or create config.json") raise SystemExit(1) return DAVClient( url=config.get("url"), username=config.get("username"), password=config.get("password"), ) ``` The documentation normalizes an HTTP endpoint: ```bash export CALDAV_URL="http://localhost:5232" export CALDAV_USER="your_username" export CALDAV_PASSWORD="your_password" ``` ### Technical Analysis The client passes credentials to any user-configured URL without validating the scheme or warning when authentication is performed over plaintext HTTP. The documented example uses loopback, which reduces exposure when used exactly as written. However, the same code accepts a remote `http://` endpoint without additional co ...[truncated 1129 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
SKILL.md:50
Finding

Plaintext CalDAV Password Storage without Permission Requirements

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/radicale.py:143
Finding

Radicale Configuration Output Does Not Redact Secrets

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (37)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The description claims a broader skill: managing CalDAV calendars and events, with special support for Radicale server, including event CRUD/query and server administration/configuration. This code chunk is narrower. It handles calendar listing, creation, deletion, inspection, and ICS import/export. While import/export touches events indirectly, there are no explicit event query, create, update, or delete commands, and no Radicale administration/configuration logic. Therefore the supplied code does not fully match the declared purpose and overstates implemented capabilities.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The description claims a broad skill for managing CalDAV calendars and events, plus administering a Radicale server. The supplied code only covers the Radicale administration portion: locating/parsing config files, checking systemd/process status, validating security/storage settings, managing htpasswd users, and verifying backend storage. There is no code to connect to a CalDAV server, enumerate calendars, or create/update/delete/query events. Because a major declared capability set (calendar and event management) is absent and the actual implementation is narrower and more server-admin oriented, this is a material description-behavior mismatch.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding

The skill advertises commands that can read environment variables, access files, write files, and execute shell commands, but it does not declare any explicit tool scope or allowed-tools boundary. In an agent setting, this weakens least-privilege controls and makes it easier for the skill to be invoked with broader capabilities than users or reviewers expect.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The examples place usernames and passwords directly in command lines and config snippets without warning that such secrets may be exposed through shell history, process listings, logs, or plaintext files. This encourages insecure credential handling and can lead to compromise of CalDAV accounts or server administration access.

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 · SKILL.md (reported line 69)May include surrounding context.

md
# List all calendars
python3 {baseDir}/scripts/calendars.py list

# Create a new calendar
python3 {baseDir}/scripts/calendars.py create --name "Work Calendar" --id work

# Delete a calendar

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The skill documents destructive actions such as deleting calendars, events, and todos without requiring confirmation or warning about irreversible effects. In an agent workflow, that increases the chance of accidental data loss from ambiguous prompts, mistaken identifiers, or automation errors.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

Administrative actions affecting Radicale users, configuration, and storage are presented without warnings about service disruption, authentication lockout, or system-wide consequences. In a skill that may be executed by an agent, missing safeguards around admin actions raises the risk of unintended outages or privilege-impacting changes.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

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

Direct HTTP/DAV Operations

For low-level operations, use curl with CalDAV:

bash
# Discover principal URL

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
82% confidence
Finding

The documentation instructs enabling and starting a system service with sudo, which requires elevated privileges and changes system state. In an agent context, normalizing privileged execution without strict gating can lead to unauthorized service modification or broader host impact if invoked carelessly.

Content

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

bash
# Enable and start
sudo systemctl enable radicale
sudo systemctl start radicale

# Check status

Session Persistence

Medium
Category
Rogue Agent
Confidence
88% confidence
Finding

systemctl enable establishes persistence by configuring the service to start automatically on boot. Persistence is not inherently malicious for legitimate administration, but in an agent skill it is security-sensitive because it creates durable system changes that may outlast the immediate user task.

Content

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

bash
# Enable and start
sudo systemctl enable radicale
sudo systemctl start radicale

# Check status

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
82% confidence
Finding

Starting the Radicale service via sudo is a privileged operation that changes host state and may expose services on the network. Without approval and scoping controls, an agent could unintentionally start or alter infrastructure components beyond the user's intent.

Content

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

bash
# Enable and start
sudo systemctl enable radicale
sudo systemctl start radicale

# Check status
sudo systemctl status radicale

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

Checking service status with sudo is a privileged-read operation and lower risk than modifying service state, but it still normalizes elevated execution. The main concern is overbroad privilege expectations within the skill rather than this command alone.

Content

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

md
sudo systemctl start radicale

# Check status
sudo systemctl status radicale

# View logs
journalctl -u radicale -f

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
85% confidence
Finding

Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Content

Scanner excerpt · scripts/calendars.py (reported line 110)May include surrounding context.

python
return
        except EOFError:
            # Non-interactive mode
            print_result(False, "Use --force to skip confirmation")
            return

    try:

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
85% confidence
Finding

Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Content

Scanner excerpt · scripts/events.py (reported line 296)May include surrounding context.

python
return
        except EOFError:
            # Non-interactive mode
            print_result(False, "Use --force to skip confirmation")
            return

    try:

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
85% confidence
Finding

Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Content

Scanner excerpt · scripts/todos.py (reported line 248)May include surrounding context.

python
return
        except EOFError:
            # Non-interactive mode
            print_result(False, "Use --force to skip confirmation")
            return

    try:

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

The export command writes full calendar contents, which may include sensitive event details, to a user-specified path. Although the operation is intentional, there is no explicit warning in code comments, docstrings, or user-facing messaging that this action stores potentially sensitive data on disk.

Content

No source excerpt is available for this finding.

Tainted flow: 'ics_content' from pathlib.Path.read_text (line 244, file read) → pathlib.Path.write_text (file write)

Medium
Category
Data Flow
Confidence
65% confidence
Finding

Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Content

Scanner excerpt · scripts/calendars.py (reported line 212)May include surrounding context.

python
if args.output:
            output_path = Path(args.output)
            output_path.write_text(ics_content)
            print_result(True, f"Exported to {args.output}", {"events": len(events)})
        else:
            print(ics_content)

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The import command reads an ICS file and transmits each VEVENT to the remote calendar via save_event, which can modify server-side user data. The code lacks a confirmation prompt or explicit disclosure that local file contents will be uploaded and remote calendar state will be changed.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/radicale.py (reported line 73)May include surrounding context.

python
# Check if service is running (systemd)
    try:
        result = subprocess.run(
            ["systemctl", "status", "radicale"],
            capture_output=True,
            text=True,

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

This skill performs host-level process and service inspection (systemctl, pgrep) that goes beyond ordinary calendar/event management into local system administration. In a tool exposed to an agent, such capabilities can disclose host topology and running services, making the skill more dangerous if the agent can invoke it without strict scope and authorization.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/radicale.py (reported line 98)May include surrounding context.

python
# Check if process is running (non-systemd)
    if data.get("service_status") != "running":
        try:
            result = subprocess.run(
                ["pgrep", "-f", "radicale"],
                capture_output=True,
                text=True,

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

config show returns the full parsed Radicale configuration, which can expose sensitive operational details such as certificate/key paths, authentication backend settings, storage locations, and other environment-specific metadata. In an agent context, even path disclosure can help an attacker map the host and target follow-on attacks.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

This code enables direct modification of the Radicale htpasswd authentication database by invoking an external command and writing to security-sensitive files. In agent-skill context, that is a powerful administrative primitive: if exposed improperly, an attacker could add accounts or alter authentication material, leading to unauthorized access to calendars or server administration.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/radicale.py (reported line 273)May include surrounding context.

python
# Check if htpasswd command exists
    try:
        subprocess.run(["htpasswd", "--help"], capture_output=True, check=True)
    except (FileNotFoundError, subprocess.CalledProcessError):
        print_result(False, "htpasswd command not found. Install apache2-utils or httpd-tools")
        return

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
80% confidence
Finding

Although the command is executed without a shell, it launches an external host binary (htpasswd) chosen via PATH and performs a privileged user-management action against a filesystem path that may come from configuration or user input. In an agent skill context, this increases risk because the skill can modify authentication state on the host and may be abused to alter admin access if exposed without strong authorization boundaries.

Content

Scanner excerpt · scripts/radicale.py (reported line 302)May include surrounding context.

python
try:
        # Run htpasswd interactively (will prompt for password)
        result = subprocess.run(cmd)
        if result.returncode == 0:
            print_result(True, f"User '{args.username}' added to {users_path}")
        else:

Static analysis

No suspicious patterns detected.