Back to skill

Security audit

remind-mcp

Security checks for vulnerabilities and agentic risk

Overview

This skill is mostly transparent about reading Remind data, but it also captures reusable session credentials and includes write-capable GraphQL mutations despite presenting itself as read-oriented.

Install only if you are comfortable granting an unpinned CLI and browser extension access to your Remind session cookies, and treat the saved session file like a password. Use the read queries only unless you intentionally want to perform live account changes or send messages, because the included mutation examples can affect real recipients and cannot necessarily be undone.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (2)

T08 · Insecure Dependencies

Warning
Location
SKILL.md:23
Finding
Unpinned Third-Party Components Receive Reusable Remind Session Credentials<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, lines 23-34 **Vulnerability Type**: Unpinned privileged dependency and supply-chain exposure **Risk Level**: Medium ### Vulnerable Code ```bash Install `@fetchproxy/cli` (`npm i -g @fetchproxy/cli`) and the **Transporter** Chrome extension. Declare the full scope **before** the first pairing — widening it later forces a re-pair: fpx profile add remind --domain remind.com fpx profile declare remind \ --capture-header cookie@www.remind.com \ --capture-header x-csrf-token@www.remind.com ``` ### Technical Analysis The Skill instructs users to install the latest available version of `@fetchproxy/cli` globally and to install a corresponding browser extension. Neither component is version-pinned or subject to an integrity-verification procedure in the instructions. These third-party components are then authorized to capture the complete Remind `Cookie` request header, including HttpOnly session cookies, as well as the CSRF token. The captured session is sufficiently privileged to read private account, class, chat, and message information and to invoke GraphQL mutations permitted to the account. The credential collection is necessary for the Skill's stated method of authenticating to Remind, and the reviewed content does not show credentials being intentionally sent to an unrelated domain. However, granting reusable session credentials to mutable, unpinned third-party components creates a significant supply-chain trust boundary. A compromised package release, extension update, distribution account, or installation source could collect those credentials. ### Attack Path 1. An attacker compromises the npm package, browser extension, maintainer account, or distribution channel. 2. A user follows the Skill and installs the latest unpinned version globally. 3. The user grants the tool permission to capture the full Remind cookie header and CSRF token. 4. The compromised component copies or trans ...[truncated 1033 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin `@fetchproxy/cli` to a specifically reviewed version rather than installing an unconstrained latest release. 2. Document the official package and extension sources and provide publisher or package-identity verification steps. 3. Verify package integrity through a lockfile, expected package digest, signed release, or equivalent mechanism. 4. Avoid global installation where possible; use an isolated environment with a locked dependency manifest. 5. Pin and verify the browser extension version where the browser platform permits it. 6. Prefer an official OAuth flow or another revocable, narrowly scoped credential mechanism if Remind provides one. 7. Minimize captured headers and session lifetime. Do not retain additional cookies that are unnecessary for the GraphQL request. 8. Document session revocation and cleanup procedures, including deleting the local session file and signing out of relevant Remind sessions after suspected compromise. 9. Clearly disclose that the bridge and extension receive credentials capable of accessing private Remind data. ]]>

other

Warning
Location
references/graphql-queries.md:125
Finding
Bundled GraphQL Mutations Exceed the Skill's Declared Read-Oriented Scope<![CDATA[ ## Vulnerability Details **File Location**: `references/graphql-queries.md`, lines 125-157 **Vulnerability Type**: Undeclared write capability and least-privilege violation **Risk Level**: Medium ### Vulnerable Code ```bash ## Mutations — read this first Writes hit real people and **cannot be unsent**. Nothing here is needed for reading Remind. **Verified live:** toggling notification devices, which affects only your own account. # disable, then re-enable, a delivery device (id from accountNotificationsScreen) rq 'mutation($i:UpdateAccountNotificationsScreenInput!){ updateAccountNotificationsScreen(input:$i){ __typename } }' \ '{"i":{"devicesToDisable":[<device-id>]}}' rq 'mutation($i:UpdateAccountNotificationsScreenInput!){ updateAccountNotificationsScreen(input:$i){ __typename } }' \ '{"i":{"devicesToEnable":[<device-id>]}}' A 200 is not proof — re-read `accountNotificationsScreen` and check `devices[].isEnabled` actually moved. **Shape only, NOT executed here** — sending a message. Check `permissions.canSend` first. rq 'mutation($i:PutMessageInput!){ putMessage(input:$i){ error { __typename } messages { __typename } } }' \ '{"i":{"recipients":[{"type":"chat","uuid":"<chat-uuid>"}],"message":{"body":"…","urgent":false}}}' `recipients[].type` is `chat` for a conversation or `group` for a whole class. **Owner/teacher only:** `scheduleMessage`, `api_scheduledMessages` and `api_deleteScheduledMessage` return `Unauthorized` on a subscriber account even with a valid session. ``` ### Technical Analysis The Skill metadata declares that it is intended to read Remind classes, chats, messages, and notification settings. The primary instructions also state that the Skill is read-oriented. Despite this declared purpose, the bundled reference contains ready-to-adapt GraphQL mutations that: - Disable or enable notification delivery devices - Send messages to a chat or an entire class The documentation warns that writes affect real users and ...[truncated 2142 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove all mutations from this read-oriented Skill and its bundled references. 2. Place write operations in a separate Skill whose metadata explicitly declares state-changing capabilities and affected recipients. 3. Change the `rq` helper to parse the GraphQL document and reject mutation operations by default. 4. Prefer an explicit allowlist of approved read-only query names or document hashes rather than accepting arbitrary GraphQL documents. 5. If writes must remain available, require clear, operation-specific confirmation immediately before submission. 6. For message operations, display the resolved recipient names, recipient count, full message body, urgency setting, and whether the target is a chat or an entire class. 7. For notification changes, display the device name and current and proposed states before confirmation. 8. Separate read and write credentials or scopes if the service provides a suitable authorization mechanism. 9. Re-read the affected state after a confirmed write and report GraphQL body errors rather than relying only on the HTTP status. ]]>
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 Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (7)

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
fpx session -p remind > ~/.remind-fpx-session.json &   # approve the pair code in Transporter
open "https://www.remind.com/"                          # feeds the capture
wait
chmod 600 ~/.remind-fpx-session.json
```

> Use a session file of your own like this one. Do **not** write into `~/.remind-mcp/` — that is
Confidence
80% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Session Persistence

Medium
Category
Rogue Agent
Content
chmod 600 ~/.remind-fpx-session.json
```

> Use a session file of your own like this one. Do **not** write into `~/.remind-mcp/` — that is
> the MCP server's store, with a different schema; overwriting it corrupts its session.

## The call pattern
Confidence
90% confidence
Finding
The skill instructs users to persist captured authenticated session material, including full cookie and CSRF token headers, in a local JSON file for reuse. Persisting reusable web-session credentials increases the risk of account compromise if the file is copied, backed up insecurely, read by other local processes, or retained longer than necessary.

External Transmission

Medium
Category
Data Exfiltration
Content
local S=~/.remind-fpx-session.json
  local body; body=$(Q="$1" V="${2:-{\}}" node -e '
    process.stdout.write(JSON.stringify({query:process.env.Q,variables:JSON.parse(process.env.V)}))')
  curl -s -X POST https://www.remind.com/graphql \
    -H 'content-type: application/json' \
    -H "cookie: $(node -e 'console.log(require(process.argv[1]).capturedHeaders.cookie)' "$S")" \
    -H "x-csrf-token: $(node -e 'console.log(require(process.argv[1]).capturedHeaders["x-csrf-token"])' "$S")" \
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Description-Behavior Mismatch

Medium
Confidence
97% confidence
Finding
The skill is presented as a read-only helper, yet it explicitly points users to mutation shapes that can perform live write actions against real users. That mismatch increases the chance of accidental misuse or policy bypass because an operator may trust the tool as non-destructive while still being guided toward message-sending capabilities.

Intent-Code Divergence

Medium
Confidence
94% confidence
Finding
Claiming the skill is 'read-oriented on purpose' while directing users to mutation details is internally inconsistent and can mislead users about the safety boundary. In a messaging platform context, that confusion matters because mutations can send irreversible communications to real recipients.

Description-Behavior Mismatch

Medium
Confidence
97% confidence
Finding
The skill is described as read-only access to Remind data, but the reference includes executable GraphQL mutations that perform state-changing actions, including toggling notification settings and a message-sending mutation shape. In a shell-oriented skill, providing ready-to-run write examples materially increases the risk that users or downstream agents will invoke unintended actions against real accounts, especially because the skill reuses an authenticated session.

Intent-Code Divergence

Low
Confidence
94% confidence
Finding
The documentation explicitly says writes are unnecessary for reading, yet still provides executable write operations in the same reference. That contradiction lowers operator trust boundaries and can mislead users or agents into believing these mutations are sanctioned parts of normal usage, increasing the chance of unintended account changes.

Static analysis

No suspicious patterns detected.