Use with caution. Address findings before production.
Scanned 5/3/2026, 6:27:28 PMยทCached resultยทFast Scanยท45 rulesยทHow we decide โ
AIVSS Score
Medium
Severity Breakdown
0
critical
15
high
9
medium
0
low
MCP Server Information
Findings
This package receives a C grade with 15 high-severity behavioral mismatches and 8 server configuration issues that could expose it to exploitation or misconfiguration attacks. The single insecure container image and medium-severity findings add additional risk, though no critical vulnerabilities were detected. You should address the high-severity behavioral mismatches and server configuration gaps before deployment, as they represent the most significant security concerns.
No known CVEs found for this package or its dependencies.
Scan Details
Want deeper analysis?
Fast scan found 24 findings using rule-based analysis. Upgrade for LLM consensus across 5 judges, AI-generated remediation, and cross-file taint analysis.
Building your own MCP server?
Same rules, same LLM judges, same grade. Private scans stay isolated to your account and never appear in the public registry. Required for code your team hasnโt shipped yet.
24 of 24 findings
24 findings
MCP tool with a destructive-sounding name is registered without the `destructiveHint: true` annotation. Clients rely on this hint to gate user confirmation, so the model may invoke the tool silently. Add `{ annotations: { destructiveHint: true } }` (TS) or `destructive_hint=True` on the tool decorator (Python).
Evidence
| 1 | """Epic-related tools for Plane MCP Server.""" |
| 2 | |
| 3 | from typing import get_args |
| 4 | |
| 5 | from fastmcp import FastMCP |
| 6 | from plane import PlaneClient |
| 7 | from plane.models.enums import PriorityEnum |
| 8 | from plane.models.epics import Epic, PaginatedEpicResponse |
| 9 | from plane.models.query_params import PaginatedQueryParams, RetrieveQueryParams |
| 10 | from plane.models.work_item_types import WorkItemType |
| 11 | from plane.models.work_items import ( |
| 12 | CreateWorkItem, |
| 13 | UpdateWorkItem, |
| 14 | ) |
| 15 | |
| 16 | from plane_mcp.client import get_plane_client_c |
Remediation
Missing annotation: add `{ annotations: { destructiveHint: true } }` as the 4th argument to `server.tool(...)` (TS) or pass `destructive_hint=True` to the `@mcp.tool(...)` decorator (Python). readOnly-lying: remove the `readOnlyHint: true` / `read_only_hint=True` assertion, or refactor the handler so it no longer calls the destructive sink. Do not suppress with a waiver โ clients rely on these hints for user-facing confirmation.
MCP tool with a destructive-sounding name is registered without the `destructiveHint: true` annotation. Clients rely on this hint to gate user confirmation, so the model may invoke the tool silently. Add `{ annotations: { destructiveHint: true } }` (TS) or `destructive_hint=True` on the tool decorator (Python).
Evidence
| 1 | """State-related tools for Plane MCP Server.""" |
| 2 | |
| 3 | from typing import Any, get_args |
| 4 | |
| 5 | from fastmcp import FastMCP |
| 6 | from plane.models.enums import GroupEnum |
| 7 | from plane.models.states import ( |
| 8 | CreateState, |
| 9 | PaginatedStateResponse, |
| 10 | State, |
| 11 | UpdateState, |
| 12 | ) |
| 13 | |
| 14 | from plane_mcp.client import get_plane_client_context |
| 15 | |
| 16 | |
| 17 | def register_state_tools(mcp: FastMCP) -> None: |
| 18 | """Register all state-related tools with the MCP server.""" |
| 19 | |
| 20 | @mcp.tool() |
| 21 | def list_states( |
| 22 | project_id: str, |
| 23 | |
Remediation
Missing annotation: add `{ annotations: { destructiveHint: true } }` as the 4th argument to `server.tool(...)` (TS) or pass `destructive_hint=True` to the `@mcp.tool(...)` decorator (Python). readOnly-lying: remove the `readOnlyHint: true` / `read_only_hint=True` assertion, or refactor the handler so it no longer calls the destructive sink. Do not suppress with a waiver โ clients rely on these hints for user-facing confirmation.
MCP tool with a destructive-sounding name is registered without the `destructiveHint: true` annotation. Clients rely on this hint to gate user confirmation, so the model may invoke the tool silently. Add `{ annotations: { destructiveHint: true } }` (TS) or `destructive_hint=True` on the tool decorator (Python).
Evidence
| 1 | """Work log-related tools for Plane MCP Server.""" |
| 2 | |
| 3 | from typing import Any |
| 4 | |
| 5 | from fastmcp import FastMCP |
| 6 | from plane.models.work_items import WorkItemWorkLog |
| 7 | |
| 8 | from plane_mcp.client import get_plane_client_context |
| 9 | |
| 10 | |
| 11 | def register_work_log_tools(mcp: FastMCP) -> None: |
| 12 | """Register all work log-related tools with the MCP server.""" |
| 13 | |
| 14 | @mcp.tool() |
| 15 | def list_work_logs( |
| 16 | project_id: str, |
| 17 | work_item_id: str, |
| 18 | params: dict[str, Any] | None = None, |
| 19 | ) -> list[WorkItemWorkLog] |
Remediation
Missing annotation: add `{ annotations: { destructiveHint: true } }` as the 4th argument to `server.tool(...)` (TS) or pass `destructive_hint=True` to the `@mcp.tool(...)` decorator (Python). readOnly-lying: remove the `readOnlyHint: true` / `read_only_hint=True` assertion, or refactor the handler so it no longer calls the destructive sink. Do not suppress with a waiver โ clients rely on these hints for user-facing confirmation.
MCP tool with a destructive-sounding name is registered without the `destructiveHint: true` annotation. Clients rely on this hint to gate user confirmation, so the model may invoke the tool silently. Add `{ annotations: { destructiveHint: true } }` (TS) or `destructive_hint=True` on the tool decorator (Python).
Evidence
| 1 | """Work item type-related tools for Plane MCP Server.""" |
| 2 | |
| 3 | from typing import Any |
| 4 | |
| 5 | from fastmcp import FastMCP |
| 6 | from plane.models.work_item_types import ( |
| 7 | CreateWorkItemType, |
| 8 | UpdateWorkItemType, |
| 9 | WorkItemType, |
| 10 | ) |
| 11 | |
| 12 | from plane_mcp.client import get_plane_client_context |
| 13 | |
| 14 | |
| 15 | def register_work_item_type_tools(mcp: FastMCP) -> None: |
| 16 | """Register all work item type-related tools with the MCP server.""" |
| 17 | |
| 18 | @mcp.tool() |
| 19 | def list_work_item_types( |
| 20 | project_id: str, |
| 21 | params: dict |
Remediation
Missing annotation: add `{ annotations: { destructiveHint: true } }` as the 4th argument to `server.tool(...)` (TS) or pass `destructive_hint=True` to the `@mcp.tool(...)` decorator (Python). readOnly-lying: remove the `readOnlyHint: true` / `read_only_hint=True` assertion, or refactor the handler so it no longer calls the destructive sink. Do not suppress with a waiver โ clients rely on these hints for user-facing confirmation.
MCP tool with a destructive-sounding name is registered without the `destructiveHint: true` annotation. Clients rely on this hint to gate user confirmation, so the model may invoke the tool silently. Add `{ annotations: { destructiveHint: true } }` (TS) or `destructive_hint=True` on the tool decorator (Python).
Evidence
| 1 | """Work item-related tools for Plane MCP Server.""" |
| 2 | |
| 3 | from typing import Any, get_args |
| 4 | |
| 5 | from fastmcp import FastMCP |
| 6 | from plane.models.enums import PriorityEnum |
| 7 | from plane.models.query_params import RetrieveQueryParams, WorkItemQueryParams |
| 8 | from plane.models.work_items import ( |
| 9 | AdvancedSearchResult, |
| 10 | AdvancedSearchWorkItem, |
| 11 | CreateWorkItem, |
| 12 | PaginatedWorkItemResponse, |
| 13 | UpdateWorkItem, |
| 14 | WorkItem, |
| 15 | WorkItemDetail, |
| 16 | WorkItemSearch, |
| 17 | ) |
| 18 | |
| 19 | from plane_mcp.client import get_plane_cli |
Remediation
Missing annotation: add `{ annotations: { destructiveHint: true } }` as the 4th argument to `server.tool(...)` (TS) or pass `destructive_hint=True` to the `@mcp.tool(...)` decorator (Python). readOnly-lying: remove the `readOnlyHint: true` / `read_only_hint=True` assertion, or refactor the handler so it no longer calls the destructive sink. Do not suppress with a waiver โ clients rely on these hints for user-facing confirmation.
MCP tool with a destructive-sounding name is registered without the `destructiveHint: true` annotation. Clients rely on this hint to gate user confirmation, so the model may invoke the tool silently. Add `{ annotations: { destructiveHint: true } }` (TS) or `destructive_hint=True` on the tool decorator (Python).
Evidence
| 1 | """Initiative-related tools for Plane MCP Server.""" |
| 2 | |
| 3 | from typing import Any |
| 4 | |
| 5 | from fastmcp import FastMCP |
| 6 | from plane.models.enums import InitiativeState |
| 7 | from plane.models.initiatives import ( |
| 8 | CreateInitiative, |
| 9 | Initiative, |
| 10 | PaginatedInitiativeResponse, |
| 11 | UpdateInitiative, |
| 12 | ) |
| 13 | |
| 14 | from plane_mcp.client import get_plane_client_context |
| 15 | |
| 16 | |
| 17 | def register_initiative_tools(mcp: FastMCP) -> None: |
| 18 | """Register all initiative-related tools with the MCP server.""" |
| 19 | |
| 20 | @mcp.tool() |
| 21 | def list_init |
Remediation
Missing annotation: add `{ annotations: { destructiveHint: true } }` as the 4th argument to `server.tool(...)` (TS) or pass `destructive_hint=True` to the `@mcp.tool(...)` decorator (Python). readOnly-lying: remove the `readOnlyHint: true` / `read_only_hint=True` assertion, or refactor the handler so it no longer calls the destructive sink. Do not suppress with a waiver โ clients rely on these hints for user-facing confirmation.
MCP tool with a destructive-sounding name is registered without the `destructiveHint: true` annotation. Clients rely on this hint to gate user confirmation, so the model may invoke the tool silently. Add `{ annotations: { destructiveHint: true } }` (TS) or `destructive_hint=True` on the tool decorator (Python).
Evidence
| 1 | """Work item comment-related tools for Plane MCP Server.""" |
| 2 | |
| 3 | from typing import Any, get_args |
| 4 | |
| 5 | from fastmcp import FastMCP |
| 6 | from plane.models.enums import AccessEnum |
| 7 | from plane.models.work_items import ( |
| 8 | CreateWorkItemComment, |
| 9 | PaginatedWorkItemCommentResponse, |
| 10 | UpdateWorkItemComment, |
| 11 | WorkItemComment, |
| 12 | ) |
| 13 | |
| 14 | from plane_mcp.client import get_plane_client_context |
| 15 | |
| 16 | |
| 17 | def register_work_item_comment_tools(mcp: FastMCP) -> None: |
| 18 | """Register all work item comment-related tools with the MCP |
Remediation
Missing annotation: add `{ annotations: { destructiveHint: true } }` as the 4th argument to `server.tool(...)` (TS) or pass `destructive_hint=True` to the `@mcp.tool(...)` decorator (Python). readOnly-lying: remove the `readOnlyHint: true` / `read_only_hint=True` assertion, or refactor the handler so it no longer calls the destructive sink. Do not suppress with a waiver โ clients rely on these hints for user-facing confirmation.
MCP tool with a destructive-sounding name is registered without the `destructiveHint: true` annotation. Clients rely on this hint to gate user confirmation, so the model may invoke the tool silently. Add `{ annotations: { destructiveHint: true } }` (TS) or `destructive_hint=True` on the tool decorator (Python).
Evidence
| 1 | """Project-related tools for Plane MCP Server.""" |
| 2 | |
| 3 | from typing import Any, get_args |
| 4 | |
| 5 | from fastmcp import FastMCP |
| 6 | from plane.models.enums import TimezoneEnum |
| 7 | from plane.models.projects import ( |
| 8 | CreateProject, |
| 9 | PaginatedProjectResponse, |
| 10 | Project, |
| 11 | ProjectFeature, |
| 12 | ProjectWorklogSummary, |
| 13 | UpdateProject, |
| 14 | ) |
| 15 | from plane.models.query_params import PaginatedQueryParams |
| 16 | from plane.models.users import UserLite |
| 17 | |
| 18 | from plane_mcp.client import get_plane_client_context |
| 19 | |
| 20 | |
| 21 | def register_project_ |
Remediation
Missing annotation: add `{ annotations: { destructiveHint: true } }` as the 4th argument to `server.tool(...)` (TS) or pass `destructive_hint=True` to the `@mcp.tool(...)` decorator (Python). readOnly-lying: remove the `readOnlyHint: true` / `read_only_hint=True` assertion, or refactor the handler so it no longer calls the destructive sink. Do not suppress with a waiver โ clients rely on these hints for user-facing confirmation.
MCP tool with a destructive-sounding name is registered without the `destructiveHint: true` annotation. Clients rely on this hint to gate user confirmation, so the model may invoke the tool silently. Add `{ annotations: { destructiveHint: true } }` (TS) or `destructive_hint=True` on the tool decorator (Python).
Evidence
| 1 | """Milestone-related tools for Plane MCP Server.""" |
| 2 | |
| 3 | from typing import Any |
| 4 | |
| 5 | from fastmcp import FastMCP |
| 6 | from plane.models.milestones import ( |
| 7 | CreateMilestone, |
| 8 | Milestone, |
| 9 | MilestoneWorkItem, |
| 10 | PaginatedMilestoneResponse, |
| 11 | PaginatedMilestoneWorkItemResponse, |
| 12 | UpdateMilestone, |
| 13 | ) |
| 14 | |
| 15 | from plane_mcp.client import get_plane_client_context |
| 16 | |
| 17 | |
| 18 | def register_milestone_tools(mcp: FastMCP) -> None: |
| 19 | """Register all milestone-related tools with the MCP server.""" |
| 20 | |
| 21 | @mcp.tool() |
| 22 | def l |
Remediation
Missing annotation: add `{ annotations: { destructiveHint: true } }` as the 4th argument to `server.tool(...)` (TS) or pass `destructive_hint=True` to the `@mcp.tool(...)` decorator (Python). readOnly-lying: remove the `readOnlyHint: true` / `read_only_hint=True` assertion, or refactor the handler so it no longer calls the destructive sink. Do not suppress with a waiver โ clients rely on these hints for user-facing confirmation.
MCP tool with a destructive-sounding name is registered without the `destructiveHint: true` annotation. Clients rely on this hint to gate user confirmation, so the model may invoke the tool silently. Add `{ annotations: { destructiveHint: true } }` (TS) or `destructive_hint=True` on the tool decorator (Python).
Evidence
| 1 | """Work item property-related tools for Plane MCP Server.""" |
| 2 | |
| 3 | from typing import Any |
| 4 | |
| 5 | from fastmcp import FastMCP |
| 6 | from plane.models.enums import PropertyType, RelationType |
| 7 | from plane.models.work_item_properties import ( |
| 8 | CreateWorkItemProperty, |
| 9 | CreateWorkItemPropertyOption, |
| 10 | PropertySettings, |
| 11 | UpdateWorkItemProperty, |
| 12 | WorkItemProperty, |
| 13 | ) |
| 14 | from plane.models.work_item_property_configurations import ( |
| 15 | DateAttributeSettings, |
| 16 | TextAttributeSettings, |
| 17 | ) |
| 18 | |
| 19 | from plane_mcp.client impo |
Remediation
Missing annotation: add `{ annotations: { destructiveHint: true } }` as the 4th argument to `server.tool(...)` (TS) or pass `destructive_hint=True` to the `@mcp.tool(...)` decorator (Python). readOnly-lying: remove the `readOnlyHint: true` / `read_only_hint=True` assertion, or refactor the handler so it no longer calls the destructive sink. Do not suppress with a waiver โ clients rely on these hints for user-facing confirmation.
MCP tool with a destructive-sounding name is registered without the `destructiveHint: true` annotation. Clients rely on this hint to gate user confirmation, so the model may invoke the tool silently. Add `{ annotations: { destructiveHint: true } }` (TS) or `destructive_hint=True` on the tool decorator (Python).
Evidence
| 1 | """Label-related tools for Plane MCP Server.""" |
| 2 | |
| 3 | from typing import Any |
| 4 | |
| 5 | from fastmcp import FastMCP |
| 6 | from plane.models.labels import ( |
| 7 | CreateLabel, |
| 8 | Label, |
| 9 | PaginatedLabelResponse, |
| 10 | UpdateLabel, |
| 11 | ) |
| 12 | |
| 13 | from plane_mcp.client import get_plane_client_context |
| 14 | |
| 15 | |
| 16 | def register_label_tools(mcp: FastMCP) -> None: |
| 17 | """Register all label-related tools with the MCP server.""" |
| 18 | |
| 19 | @mcp.tool() |
| 20 | def list_labels( |
| 21 | project_id: str, |
| 22 | params: dict[str, Any] | None = None, |
| 23 | ) -> lis |
Remediation
Missing annotation: add `{ annotations: { destructiveHint: true } }` as the 4th argument to `server.tool(...)` (TS) or pass `destructive_hint=True` to the `@mcp.tool(...)` decorator (Python). readOnly-lying: remove the `readOnlyHint: true` / `read_only_hint=True` assertion, or refactor the handler so it no longer calls the destructive sink. Do not suppress with a waiver โ clients rely on these hints for user-facing confirmation.
MCP tool with a destructive-sounding name is registered without the `destructiveHint: true` annotation. Clients rely on this hint to gate user confirmation, so the model may invoke the tool silently. Add `{ annotations: { destructiveHint: true } }` (TS) or `destructive_hint=True` on the tool decorator (Python).
Evidence
| 1 | """Cycle-related tools for Plane MCP Server.""" |
| 2 | |
| 3 | from typing import Any |
| 4 | |
| 5 | from fastmcp import FastMCP |
| 6 | from plane.models.cycles import ( |
| 7 | CreateCycle, |
| 8 | Cycle, |
| 9 | PaginatedArchivedCycleResponse, |
| 10 | PaginatedCycleResponse, |
| 11 | PaginatedCycleWorkItemResponse, |
| 12 | TransferCycleWorkItemsRequest, |
| 13 | UpdateCycle, |
| 14 | ) |
| 15 | from plane.models.work_items import WorkItem |
| 16 | |
| 17 | from plane_mcp.client import get_plane_client_context |
| 18 | |
| 19 | |
| 20 | def register_cycle_tools(mcp: FastMCP) -> None: |
| 21 | """Register all cycle-related |
Remediation
Missing annotation: add `{ annotations: { destructiveHint: true } }` as the 4th argument to `server.tool(...)` (TS) or pass `destructive_hint=True` to the `@mcp.tool(...)` decorator (Python). readOnly-lying: remove the `readOnlyHint: true` / `read_only_hint=True` assertion, or refactor the handler so it no longer calls the destructive sink. Do not suppress with a waiver โ clients rely on these hints for user-facing confirmation.
MCP tool with a destructive-sounding name is registered without the `destructiveHint: true` annotation. Clients rely on this hint to gate user confirmation, so the model may invoke the tool silently. Add `{ annotations: { destructiveHint: true } }` (TS) or `destructive_hint=True` on the tool decorator (Python).
Evidence
| 1 | """Intake work item-related tools for Plane MCP Server.""" |
| 2 | |
| 3 | from typing import Any |
| 4 | |
| 5 | from fastmcp import FastMCP |
| 6 | from plane.models.intake import ( |
| 7 | CreateIntakeWorkItem, |
| 8 | IntakeWorkItem, |
| 9 | PaginatedIntakeWorkItemResponse, |
| 10 | UpdateIntakeWorkItem, |
| 11 | ) |
| 12 | from plane.models.query_params import PaginatedQueryParams, RetrieveQueryParams |
| 13 | |
| 14 | from plane_mcp.client import get_plane_client_context |
| 15 | |
| 16 | |
| 17 | def register_intake_tools(mcp: FastMCP) -> None: |
| 18 | """Register all intake work item-related tools with t |
Remediation
Missing annotation: add `{ annotations: { destructiveHint: true } }` as the 4th argument to `server.tool(...)` (TS) or pass `destructive_hint=True` to the `@mcp.tool(...)` decorator (Python). readOnly-lying: remove the `readOnlyHint: true` / `read_only_hint=True` assertion, or refactor the handler so it no longer calls the destructive sink. Do not suppress with a waiver โ clients rely on these hints for user-facing confirmation.
MCP tool with a destructive-sounding name is registered without the `destructiveHint: true` annotation. Clients rely on this hint to gate user confirmation, so the model may invoke the tool silently. Add `{ annotations: { destructiveHint: true } }` (TS) or `destructive_hint=True` on the tool decorator (Python).
Evidence
| 1 | """Work item link-related tools for Plane MCP Server.""" |
| 2 | |
| 3 | from typing import Any |
| 4 | |
| 5 | from fastmcp import FastMCP |
| 6 | from plane.models.work_items import ( |
| 7 | CreateWorkItemLink, |
| 8 | PaginatedWorkItemLinkResponse, |
| 9 | UpdateWorkItemLink, |
| 10 | WorkItemLink, |
| 11 | ) |
| 12 | |
| 13 | from plane_mcp.client import get_plane_client_context |
| 14 | |
| 15 | |
| 16 | def register_work_item_link_tools(mcp: FastMCP) -> None: |
| 17 | """Register all work item link-related tools with the MCP server.""" |
| 18 | |
| 19 | @mcp.tool() |
| 20 | def list_work_item_links( |
| 21 | project |
Remediation
Missing annotation: add `{ annotations: { destructiveHint: true } }` as the 4th argument to `server.tool(...)` (TS) or pass `destructive_hint=True` to the `@mcp.tool(...)` decorator (Python). readOnly-lying: remove the `readOnlyHint: true` / `read_only_hint=True` assertion, or refactor the handler so it no longer calls the destructive sink. Do not suppress with a waiver โ clients rely on these hints for user-facing confirmation.
MCP tool with a destructive-sounding name is registered without the `destructiveHint: true` annotation. Clients rely on this hint to gate user confirmation, so the model may invoke the tool silently. Add `{ annotations: { destructiveHint: true } }` (TS) or `destructive_hint=True` on the tool decorator (Python).
Evidence
| 1 | """Module-related tools for Plane MCP Server.""" |
| 2 | |
| 3 | from typing import Any, get_args |
| 4 | |
| 5 | from fastmcp import FastMCP |
| 6 | from plane.models.enums import ModuleStatusEnum |
| 7 | from plane.models.modules import ( |
| 8 | CreateModule, |
| 9 | Module, |
| 10 | PaginatedArchivedModuleResponse, |
| 11 | PaginatedModuleResponse, |
| 12 | PaginatedModuleWorkItemResponse, |
| 13 | UpdateModule, |
| 14 | ) |
| 15 | from plane.models.work_items import WorkItem |
| 16 | |
| 17 | from plane_mcp.client import get_plane_client_context |
| 18 | |
| 19 | |
| 20 | def register_module_tools(mcp: FastMCP) -> None: |
| 21 | |
Remediation
Missing annotation: add `{ annotations: { destructiveHint: true } }` as the 4th argument to `server.tool(...)` (TS) or pass `destructive_hint=True` to the `@mcp.tool(...)` decorator (Python). readOnly-lying: remove the `readOnlyHint: true` / `read_only_hint=True` assertion, or refactor the handler so it no longer calls the destructive sink. Do not suppress with a waiver โ clients rely on these hints for user-facing confirmation.
Service binds to 0.0.0.0 โ all network interfaces. For MCP servers that only need to talk to a single parent process, bind to 127.0.0.1 (or a Unix domain socket) instead.
Evidence
| 130 | logger.info("Starting HTTP server at URLs: /mcp and /header/mcp") |
| 131 | uvicorn.run( |
| 132 | app, |
| 133 | host="0.0.0.0", |
| 134 | port=8211, |
| 135 | log_level="info", |
| 136 | access_log=False, |
Remediation
Bind to 127.0.0.1 for local-only access. If cross-host access is truly required, put the service behind an authenticated reverse proxy rather than exposing it on 0.0.0.0.
Dockerfile never sets a non-root `USER` directive, so the CMD runs as root by default. Any RCE or library-level vulnerability exploited inside this container gets full privileges (MCP Top-10 R3). Add `USER <non-root>` before CMD / ENTRYPOINT in the final stage โ e.g. `USER 1000`, `USER nobody`, or `USER nonroot` on distroless.
Evidence
| 1 | # Use Python 3.11 as base image |
| 2 | FROM python:3.11-slim |
| 3 | |
| 4 | # Set working directory |
| 5 | WORKDIR /app |
| 6 | |
| 7 | # Install system dependencies |
| 8 | RUN apt-get update && apt-get install -y \ |
| 9 | curl \ |
| 10 | && rm -rf /var/lib/apt/lists/* |
| 11 | |
| 12 | # Install uv for faster package management |
| 13 | COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv |
| 14 | |
| 15 | # Copy dependency files and application code |
| 16 | COPY pyproject.toml ./ |
| 17 | COPY uv.lock* ./ |
| 18 | COPY plane_mcp/ ./plane_mcp/ |
| 19 | |
| 20 | # Install the package and dependencies using uv |
| 21 | RUN uv pip install |
Remediation
Create and switch to a non-root user before the CMD / ENTRYPOINT: RUN adduser --system --uid 1000 app USER 1000 Or reuse the base image's shipped non-root account (e.g. `USER nobody`, `USER nonroot` on distroless). Multi-stage builds only need the USER directive in the final stage.
GitHub Actions `uses:` reference is not pinned to a 40-character commit SHA. Tags (`@v4`) and branches (`@main`) are mutable โ a compromised maintainer or a tag rewrite can substitute malicious code into your CI pipeline silently. Pin to a SHA: `uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab`. For readability, include the version as a trailing comment: `# v4.1.1`. Tools like `pinact` / `ratchet` automate this. Allowed unpinned forms (excluded by the rule): - Local actions `.
Evidence
| 49 | echo "current-version=$VERSION" >> $GITHUB_OUTPUT |
| 50 | |
| 51 | - name: Create GitHub Release |
| 52 | uses: softprops/action-gh-release@v2 |
| 53 | with: |
| 54 | tag_name: v${{ steps.package-version.outputs.current-version }} |
| 55 | name: v${{ steps.package-version.outputs.current-version }} |
Remediation
Pin every `uses:` to a 40-character commit SHA. Trailing comment with the version helps reviewers: `uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v4.1.1` Automate the migration with `pinact` (https://github.com/suzuki-shunsuke/pinact) or `ratchet` (https://github.com/sethvargo/ratchet). Add a `pinact run --check` pre-commit hook so future PRs stay pinned. Re-pin when the action releases a new version โ Dependabot can do this automatically with `version-update-strategy: inc
GitHub Actions `uses:` reference is not pinned to a 40-character commit SHA. Tags (`@v4`) and branches (`@main`) are mutable โ a compromised maintainer or a tag rewrite can substitute malicious code into your CI pipeline silently. Pin to a SHA: `uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab`. For readability, include the version as a trailing comment: `# v4.1.1`. Tools like `pinact` / `ratchet` automate this. Allowed unpinned forms (excluded by the rule): - Local actions `.
Evidence
| 95 | name: Checkout Files |
| 96 | uses: actions/checkout@v4 |
| 97 | - name: Plane MCP Server Build and Push |
| 98 | uses: makeplane/actions/build-push@v1.0.0 |
| 99 | with: |
| 100 | build-release: ${{ needs.release_build_setup.outputs.build_release }} |
| 101 | build-prerelease: ${{ needs.release_build_setup.outputs.build_prerelease }} |
Remediation
Pin every `uses:` to a 40-character commit SHA. Trailing comment with the version helps reviewers: `uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v4.1.1` Automate the migration with `pinact` (https://github.com/suzuki-shunsuke/pinact) or `ratchet` (https://github.com/sethvargo/ratchet). Add a `pinact run --check` pre-commit hook so future PRs stay pinned. Re-pin when the action releases a new version โ Dependabot can do this automatically with `version-update-strategy: inc
GitHub Actions `uses:` reference is not pinned to a 40-character commit SHA. Tags (`@v4`) and branches (`@main`) are mutable โ a compromised maintainer or a tag rewrite can substitute malicious code into your CI pipeline silently. Pin to a SHA: `uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab`. For readability, include the version as a trailing comment: `# v4.1.1`. Tools like `pinact` / `ratchet` automate this. Allowed unpinned forms (excluded by the rule): - Local actions `.
Evidence
| 12 | steps: |
| 13 | - name: Checkout code |
| 14 | uses: actions/checkout@v4 |
| 15 | |
| 16 | - name: Set up Python |
| 17 | uses: actions/setup-python@v4 |
Remediation
Pin every `uses:` to a 40-character commit SHA. Trailing comment with the version helps reviewers: `uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v4.1.1` Automate the migration with `pinact` (https://github.com/suzuki-shunsuke/pinact) or `ratchet` (https://github.com/sethvargo/ratchet). Add a `pinact run --check` pre-commit hook so future PRs stay pinned. Re-pin when the action releases a new version โ Dependabot can do this automatically with `version-update-strategy: inc
GitHub Actions `uses:` reference is not pinned to a 40-character commit SHA. Tags (`@v4`) and branches (`@main`) are mutable โ a compromised maintainer or a tag rewrite can substitute malicious code into your CI pipeline silently. Pin to a SHA: `uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab`. For readability, include the version as a trailing comment: `# v4.1.1`. Tools like `pinact` / `ratchet` automate this. Allowed unpinned forms (excluded by the rule): - Local actions `.
Evidence
| 15 | uses: actions/checkout@v4 |
| 16 | |
| 17 | - name: Set up Python |
| 18 | uses: actions/setup-python@v4 |
| 19 | with: |
| 20 | python-version: "3.10" |
Remediation
Pin every `uses:` to a 40-character commit SHA. Trailing comment with the version helps reviewers: `uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v4.1.1` Automate the migration with `pinact` (https://github.com/suzuki-shunsuke/pinact) or `ratchet` (https://github.com/sethvargo/ratchet). Add a `pinact run --check` pre-commit hook so future PRs stay pinned. Re-pin when the action releases a new version โ Dependabot can do this automatically with `version-update-strategy: inc
GitHub Actions `uses:` reference is not pinned to a 40-character commit SHA. Tags (`@v4`) and branches (`@main`) are mutable โ a compromised maintainer or a tag rewrite can substitute malicious code into your CI pipeline silently. Pin to a SHA: `uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab`. For readability, include the version as a trailing comment: `# v4.1.1`. Tools like `pinact` / `ratchet` automate this. Allowed unpinned forms (excluded by the rule): - Local actions `.
Evidence
| 128 | - name: Create Release |
| 129 | id: create_release |
| 130 | uses: softprops/action-gh-release@v2.1.0 |
| 131 | env: |
| 132 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, you do not need to create your own token |
| 133 | with: |
Remediation
Pin every `uses:` to a 40-character commit SHA. Trailing comment with the version helps reviewers: `uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v4.1.1` Automate the migration with `pinact` (https://github.com/suzuki-shunsuke/pinact) or `ratchet` (https://github.com/sethvargo/ratchet). Add a `pinact run --check` pre-commit hook so future PRs stay pinned. Re-pin when the action releases a new version โ Dependabot can do this automatically with `version-update-strategy: inc
GitHub Actions `uses:` reference is not pinned to a 40-character commit SHA. Tags (`@v4`) and branches (`@main`) are mutable โ a compromised maintainer or a tag rewrite can substitute malicious code into your CI pipeline silently. Pin to a SHA: `uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab`. For readability, include the version as a trailing comment: `# v4.1.1`. Tools like `pinact` / `ratchet` automate this. Allowed unpinned forms (excluded by the rule): - Local actions `.
Evidence
| 124 | REL_VERSION: ${{ needs.release_build_setup.outputs.release_version }} |
| 125 | steps: |
| 126 | - name: Checkout |
| 127 | uses: actions/checkout@v4 |
| 128 | |
| 129 | - name: Create Release |
| 130 | id: create_release |
Remediation
Pin every `uses:` to a 40-character commit SHA. Trailing comment with the version helps reviewers: `uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v4.1.1` Automate the migration with `pinact` (https://github.com/suzuki-shunsuke/pinact) or `ratchet` (https://github.com/sethvargo/ratchet). Add a `pinact run --check` pre-commit hook so future PRs stay pinned. Re-pin when the action releases a new version โ Dependabot can do this automatically with `version-update-strategy: inc
GitHub Actions `uses:` reference is not pinned to a 40-character commit SHA. Tags (`@v4`) and branches (`@main`) are mutable โ a compromised maintainer or a tag rewrite can substitute malicious code into your CI pipeline silently. Pin to a SHA: `uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab`. For readability, include the version as a trailing comment: `# v4.1.1`. Tools like `pinact` / `ratchet` automate this. Allowed unpinned forms (excluded by the rule): - Local actions `.
Evidence
| 93 | steps: |
| 94 | - id: checkout_files |
| 95 | name: Checkout Files |
| 96 | uses: actions/checkout@v4 |
| 97 | - name: Plane MCP Server Build and Push |
| 98 | uses: makeplane/actions/build-push@v1.0.0 |
| 99 | with: |
Remediation
Pin every `uses:` to a 40-character commit SHA. Trailing comment with the version helps reviewers: `uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v4.1.1` Automate the migration with `pinact` (https://github.com/suzuki-shunsuke/pinact) or `ratchet` (https://github.com/sethvargo/ratchet). Add a `pinact run --check` pre-commit hook so future PRs stay pinned. Re-pin when the action releases a new version โ Dependabot can do this automatically with `version-update-strategy: inc
list_epics
list_states
list_work_logs
list_work_item_types
list_work_items
list_initiatives
list_work_item_comments
list_projects
list_milestones
list_work_item_properties
list_labels
list_cycles
list_intake_work_items
list_work_item_links
list_modules