Back to skill

Security audit

Scheduly

Security checks for vulnerabilities and agentic risk

Overview

This scheduling API is mostly purpose-aligned, but it exposes sensitive booking, calendar, availability, renewal, and scheduler operations without documented authentication, authorization, or confirmation controls.

Review this before installing or granting real access. It is not clearly malicious, but it should not be used for production scheduling data unless the provider documents and enforces authentication, ownership checks, explicit confirmation for destructive or paid actions, and internal-only protection for the scheduler endpoint. Treat guest names, emails, notes, Google connection state, and coin renewals as sensitive.

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)

T05 · Unauthorized Access and Privilege Escalation

Error
Location
openapi.json:588
Finding

Booking Data and Cancellation Operations Lack Declared Authentication

Content
View full analysis

Vulnerability Details

File Location: openapi.json:588-704
Vulnerability Type: Broken object-level authorization caused by reliance on caller-controlled user identifiers
Risk Level: High

Vulnerable Code

json
"/bookings": {
  "post": {
    "summary": "Create Booking",
    "description": "Create a new booking",
    "operationId": "create_booking_bookings_post",
    "requestBody": {
      "required": true,
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/BookingCreate"
          }
        }
      }
    }
  },
  "get": {
    "summary": "Get Bookings",
    "description": "Get all bookings for a user",
    "operationId": "get_bookings_bookings_get",
    "parameters": [
      {
        "name": "user_id",
        "in": "query",
        "required": true,
        "schema": {
          "type": "string",
          "title": "User Id"
        }
      }
    ]
  }
},
"/bookings/{booking_id}": {
  "delete": {
    "summary": "Cancel Booking",
    "description": "Cancel a booking",
    "operationId": "cancel_booking_bookings__booking_id__delete",
    "parameters": [
      {
        "name": "booking_id",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string",
          "title": "Booking Id"
        }
      },
      {
        "name": "user_id",
        "in": "query",
        "required": true,
        "schema": {
          "type": "string",
          "title": "User Id"
        }
      }
    ]
  }
}

Technical Analysis

The OpenAPI contract declares neither a global authentication requirement nor operation-level security requirements. Its components section also contains no securitySchemes. Access to all bookings and cancellation operations is represented as depending only on caller-supplied user_id and `book ...[truncated 1864 chars]

Remediation
View remediation

Remediation Suggestions

  • Define and enforce OAuth 2.0, signed API keys, or authenticated sessions through an OpenAPI securitySchemes entry and global or operation-level security requirements.
  • Derive the acting user identity from validated credentials rather than accepting user_id as authorization evidence.
  • On every object access, verify that the authenticated principal owns or is explicitly authorized to access the requested booking.
  • Use opaque, high-entropy booking identifiers as defense in depth, while retaining mandatory ownership checks.
  • Return 401 Unauthorized when credentials are missing and 403 Forbidden when the principal lacks access.
  • Apply equivalent authorization checks to event types, availability, blocked dates, user settings, renewals, and Google Calendar operations.
  • Add automated negative tests that attempt cross-account reads, updates, and deletions with valid credentials from a different user.
  • Document all security requirements in the API specification so generated clients cannot invoke sensitive operations as though they were public.

T05 · Unauthorized Access and Privilege Escalation

Error
Location
openapi.json:1075
Finding

Public Scheduler Endpoint Can Trigger Global Renewal and Notification Processing

Content
View full analysis

Vulnerability Details

File Location: openapi.json:1075-1092
Vulnerability Type: Unauthenticated privileged administrative operation
Risk Level: High

Vulnerable Code

json
"/scheduler/process-expirations": {
  "post": {
    "summary": "Process Expirations",
    "description": "Process all expiring events, auto-renewals, and send notifications\nThis should be called daily by a cron job",
    "operationId": "process_expirations_scheduler_process_expirations_post",
    "responses": {
      "200": {
        "description": "Successful Response",
        "content": {
          "application/json": {
            "schema": {}
          }
        }
      }
    }
  }
}

Technical Analysis

This endpoint is described as a cron-only operation that processes all expiring events, performs auto-renewals, and sends notifications. However, it has no declared authentication parameter, service credential, authorization scope, or OpenAPI security requirement.

According to SKILL.md, event renewal costs 500 coins. Consequently, this is a privileged, account-wide operation with potential financial and messaging side effects. Exposing it through a public route permits arbitrary callers to trigger processing outside the intended daily schedule.

Repeated requests may also create race conditions, duplicate processing, notification spam, or resource exhaustion if the backend lacks transactional locking and idempotency. The supplied artifacts do not demonstrate such protections.

Attack Path

  1. Identify the API base URL from the Skill documentation.
  2. Send an unauthenticated POST request to /scheduler/process-expirations.
  3. Repeat or parallelize requests to invoke global expiration processing outside the intended cron schedule.
  4. Cause repeated renewal attempts, notification delivery, or resource-intensive scans if backend processing is not strongly idempotent and serialized.

...[truncated 647 chars]

Remediation
View remediation

Remediation Suggestions

  • Remove this operation from the public API and invoke expiration processing through an internal job queue or scheduler.
  • If an HTTP trigger is required, place it on a private network and require strong machine-to-machine authentication, such as mutual TLS or a short-lived service token.
  • Define a dedicated authorization scope that cannot be granted to ordinary users.
  • Restrict source networks and reject requests received through public ingress.
  • Make processing idempotent for each event and billing period.
  • Use transactional locks or distributed leases to ensure that only one scheduler instance processes a renewal batch.
  • Add replay protection, strict rate limits, audit logging, and alerts for unexpected invocation frequency.
  • Ensure billing operations use unique transaction keys so retries cannot create duplicate charges.

T09 · Insecure Skill Coding Practices

Warning
Location
SKILL.md:239
Finding

Availability Responses Disclose Booked Guest Names

Content
View full analysis

Vulnerability Details

File Location: SKILL.md:239-252
Vulnerability Type: Excessive data exposure and guest privacy disclosure
Risk Level: Medium

Vulnerable Code

markdown
#### `GET /available-slots`
Get time slots with availability status for a specific date.

**Parameters:**
- `user_id` (string, required): Unique user identifier
- `event_type_slug` (string, required): Event type slug
- `date` (string, required): Date in YYYY-MM-DD format

**Response:** Array of available time slots with:
- `time`: Slot time in HH:MM format
- `available`: Boolean availability status
- `booked_by`: Guest name if booked

Technical Analysis

Slot discovery only requires a caller to provide a user identifier, event slug, and date. Nevertheless, the documented response includes booked_by, revealing the guest's name whenever a slot is occupied.

A guest's identity is unnecessary for determining whether a time slot is available. Returning it violates data-minimization principles and enables unauthenticated identity enumeration. Public booking URLs may also expose the user identifier and event slug needed to query dates.

Attack Path

  1. Obtain a scheduling user's identifier and event slug from a public booking page or shared booking link.
  2. Enumerate dates using GET /available-slots?user_id=<user>&event_type_slug=<slug>&date=<date>.
  3. Record occupied slots and their booked_by values.
  4. Repeat across dates and event types to build a history of guest identities and appointment patterns.

Impact Assessment

Exploitation can expose client, patient, customer, or business-contact identities and correlate those identities with appointment dates and times. This may permit profiling, targeted social engineering, inference of professional relationships, or privacy violations. The scope includes every guest name returned through enumerable user, event, and date combinat ...[truncated 5 chars]

Remediation
View remediation

Remediation Suggestions

  • Remove booked_by from all public and availability-oriented responses.
  • Return only the slot time and a boolean or generic occupied status.
  • Restrict detailed booking records to authenticated account owners with explicit object-level authorization.
  • Apply response DTOs or schema allowlists so private guest fields cannot accidentally appear in public responses.
  • Rate-limit date and slot enumeration and monitor systematic scraping behavior.
  • Review other public responses for guest emails, notes, calendar metadata, or internal identifiers that are not required for booking.
  • Add privacy-focused API tests asserting that public slot responses never contain guest identity or contact information.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (19)

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
88% confidence
Finding

DELETE /event-types/{event_id} is a destructive operation identified only by a user-supplied ID and documented user_id parameter, with no mention of authorization controls, confirmation, or anti-abuse protections. In an agent context, parameter tampering or mistaken ID selection could delete another event configuration or cause loss of scheduling availability.

Content

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

md
---

#### `DELETE /event-types/{event_id}`
Delete an event type.

**Parameters:**

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
90% confidence
Finding

DELETE /bookings/{booking_id} allows cancellation of bookings using an identifier and documented user_id, but the skill description does not describe safeguards such as ownership validation, cancellation authorization, or confirmation. This creates a risk of unauthorized or accidental booking cancellation, directly impacting service delivery and user trust.

Content

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

md
---

#### `DELETE /bookings/{booking_id}`
Cancel a booking.

**Parameters:**

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
86% confidence
Finding

DELETE /blocked-dates/{blocked_id} is another destructive endpoint with no documented confirmation or authorization detail, making it susceptible to misuse through incorrect IDs or insufficient access control assumptions. Removing blocked dates can reopen unavailable time slots and lead to unauthorized or conflicting bookings.

Content

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

md
---

#### `DELETE /blocked-dates/{blocked_id}`
Remove a blocked date.

**Parameters:**

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 30)May include surrounding context.

Request:

bash
curl -X POST https://api.toolweb.in/tools/scheduly/event-types \
  -H "Content-Type: application/json" \
  -d '{
    "name": "30-Minute Consultation",

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% 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 30)May include surrounding context.

Request:

bash
curl -X POST https://api.toolweb.in/tools/scheduly/event-types \
  -H "Content-Type: application/json" \
  -d '{
    "name": "30-Minute Consultation",

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% 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 76)May include surrounding context.

Request:

bash
curl -X POST https://api.toolweb.in/tools/scheduly/event-types \
  -H "Content-Type: application/json" \
  -d '{
    "name": "30-Minute Consultation",

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% 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 457)May include surrounding context.

Request:

bash
curl -X POST https://api.toolweb.in/tools/scheduly/event-types \
  -H "Content-Type: application/json" \
  -d '{
    "name": "30-Minute Consultation",

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The skill exposes destructive or account-affecting operations such as disconnecting Google accounts and deleting event types without documenting any confirmation, authorization, or user-warning safeguards. In an agent setting, this increases the chance of accidental or prompt-induced destructive actions that can disrupt calendars, bookings, and account state.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The documented WordPress name sync is outside the declared scope of a scheduling API with Google Calendar integration, creating a mismatch between advertised behavior and actual data access. Such hidden or under-disclosed integrations are dangerous because they undermine informed consent and can enable unintended collection or propagation of user identity data.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The /user/sync-wordpress-name endpoint expands the skill's capabilities beyond the stated scheduling and Google Calendar purpose into third-party profile synchronization. This kind of scope drift increases privacy and data-flow risk because an agent or user may disclose or fetch WordPress-linked identity data without that behavior being clearly justified in the skill description.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

This manifest documents a POST operation that disconnects Google Calendar and removes tokens, which is a potentially irreversible account-impacting action. The description states what it does but provides no explicit caution, confirmation requirement, or user-facing warning about the loss of integration access.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The manifest describes scheduling, booking management, Google Calendar integration, event type management, availability rules, and booking capabilities. However, the API also exposes coin-based billing and subscription-style expiration/renewal behavior for event types, which is a distinct product capability not disclosed in the stated description.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
84% confidence
Finding

The API spec exposes a DELETE operation for event types, which is a destructive action affecting user data. The description only says 'Delete event type' and does not warn that the operation removes the event type or advise confirmation before execution.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
79% confidence
Finding

This endpoint enables or disables auto-renewal, and elsewhere the spec states renewals cost coins, so changing this setting can affect future account balances or recurring behavior. The description omits any warning that enabling auto-renewal may trigger future paid renewals automatically.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
82% confidence
Finding

The DELETE booking endpoint performs a cancellation that affects scheduled user data and may be difficult to reverse. The spec provides no explicit caution, side-effect notice, or suggestion that clients confirm the cancellation with the user first.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The manifest mentions Google Calendar integration, event types, availability rules, and bookings, but does not mention any WordPress integration. Fetching and syncing a WordPress user's display name introduces an unrelated third-party identity/content-platform capability that is not an obvious requirement of scheduling operations.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
80% confidence
Finding

Removing a blocked date changes availability and can expose time slots that were intentionally unavailable, which is a user-impacting destructive change. The description simply states the action without any warning or confirmation guidance.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The API exposes a scheduler endpoint that processes expirations, auto-renewals, and notifications, but the spec shows no authentication, authorization, or internal-only restriction. If externally callable, an attacker could trigger billing/resource lifecycle actions or notification workflows out of schedule, causing unauthorized state changes or operational abuse.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
85% confidence
Finding

A scheduled job endpoint with automated side effects such as expirations, renewals, and notifications is dangerous when exposed without clearly indicated access restrictions. Attackers could invoke it repeatedly to force premature processing, spam notifications, or trigger unintended renewals and lifecycle transitions.

Content

No source excerpt is available for this finding.