MCP Vendor Intelligence
Third-PartyWraps HubSpot

@shinzolabs/hubspot-mcp

by Shinzo Labsv2.0.5Updated 2025-11-25

A community-built HubSpot MCP with the broadest tool coverage in our corpus (112 tools across HubSpot's full CRM surface), but with significant disclosure-versus-reality gaps. The package's PRIVACY.md states telemetry doesn't transmit IP or port; the runtime does. An undeclared HTTP server runs alongside the documented stdio mode that would expose HubSpot credentials if reachable on a network. The production dependency tree carries 17 known vulnerabilities (2 critical, 5 high), and telemetry defaults to 100% sampling with a 5-second export interval. If you need broad HubSpot tool coverage and you can run this in a tightly-controlled environment, the tool surface is real; for environments with privacy, compliance, or supply-chain attestation requirements, this MCP doesn't currently meet the bar.

6 findings6 BTI-M codes
Max severity (buyer-facing)
HIGH

How To Read This Profile

BLACKOUT performed static analysis of the published npm package and supporting documentation, classified each behavior using our BTI-M (Behavioral Threat Intelligence — MCP runtime) taxonomy, and recorded findings with severity calibrated from a buyer's perspective. Anomalies below the findings list are hygiene observations that may not directly affect security but contribute to the overall trust posture.

Overview

What This MCP Does

Who built it. Shinzo Labs — a small independent publisher. Published as @shinzolabs/hubspot-mcp on npm, version 2.0.5. Source is public on GitHub.

What it does. Provides 112 MCP tools spanning HubSpot's CRM API surface: companies, contacts, deals, leads, engagements (calls, emails, meetings, notes, tasks), associations, products, and communication preferences. The broadest tool coverage of any HubSpot MCP we've analyzed.

What it collects. A HubSpot access token from the environment. Then, by default, telemetry: every tool call, including the IP address and port of the host running the MCP server, is sent to Shinzo Labs' own telemetry collector. The package's PRIVACY.md states IP and port are not transmitted; the runtime contradicts that claim.

What it stores. Nothing on disk. However, an undeclared HTTP server is started alongside the documented stdio mode — if the listening port is reachable from the network, the running MCP could be invoked by unauthenticated callers.

Where data goes. HubSpot's API for tool calls. Shinzo Labs' own telemetry collector for telemetry by default. Telemetry can be disabled via an environment variable, but the opt-out has fragile string-equality semantics — common variants of "off" don't work, only one exact value does.

Findings

6 Findings

6 BTI-M CODES

Each finding maps to one or more BTI-M codes. Buyer-facing severity reflects how a reasonable buyer should weigh the issue when deciding whether to deploy this MCP. Code review severity (when shown separately) is the analyst's view of the underlying defect or design choice.

Finding 1BTI-M05MCP-S-SHINZO-001

Telemetry transmits your IP address and port despite the privacy policy stating it doesn't

HIGH

The package's PRIVACY.md explicitly states that telemetry doesn't include IP address or port. The runtime, however, packages both into every telemetry submission to the vendor's collector domain. This is a direct claims-versus-reality gap: the privacy disclosure says one thing, the code does another. Buyers evaluating the MCP based on the privacy policy alone get a materially different picture than what's actually shipped.

Evidence (7 references)
  • PRIVACY.md:35-42 — "### What We DO NOT Collect ... IP addresses and Ports: Your network information"
    • node_modules/@shinzolabs/instrumentation-mcp/dist/utils.js:43-62getRuntimeInfo() extracts the first non-internal IPv4 from os.networkInterfaces() and reads process.env.PORT, returning { address, port }
    • node_modules/@shinzolabs/instrumentation-mcp/dist/instrumentation.js:64-84 — these values are attached to every tool span as client.address and client.port attributes
    • src/index.ts:91-97instrumentServer(server, { ..., exporterEndpoint: "https://api.otel.shinzo.tech/v1" }) activates this pipeline by default
    • The PII sanitizer's redactPIIAttributes() (sanitizer.js:16-25) replaces client.address and client.port only at the resource level. The instrumentation library re-applies them at the span level, where neither the key-name allow-list (sanitizer.js:62-69) nor the regex patterns (sanitizer.js:7-14) catch a bare IPv4 string or a port number — the values pass through unredacted.
Also cites:BTI-X02
Finding 2BTI-M01MCP-S-SHINZO-002

An undeclared HTTP server runs alongside stdio mode and would expose HubSpot credentials if reachable

HIGH

When the package runs in its documented stdio mode, it also silently starts an HTTP server on a local port. The README doesn't mention this, the privacy policy doesn't disclose it, and the listener requires no authentication. If the host is configured such that the port is reachable from the network — through a firewall misconfiguration, a Docker port forward, or a development environment exposed to a LAN — anything that can connect to the port can issue MCP commands as the running process, with the configured HubSpot access token.

Evidence (3 references)
  • src/index.ts:2523-2531:
    // Stdio Server
    const stdioServer = createServer({})
    const transport = new StdioServerTransport()
    await stdioServer.connect(transport)
    
    // Streamable HTTP Server
    const { app } = createStatefulServer(createServer)
    const PORT = process.env.PORT || 3000
    app.listen(PORT)
    
    • node_modules/.pnpm/@smithery+sdk@1.4.3.../dist/server/stateful.js:14-87 — Express app exposes POST /mcp, GET /mcp, DELETE /mcp with no authentication middleware. Session is created on any well-formed initialize request.
    • src/index.ts:74-79getConfig() falls back to process.env.HUBSPOT_ACCESS_TOKEN when the request does not supply a config object.
    • app.listen(PORT) is called without a host argument; per Node.js semantics this binds to all interfaces (:: / 0.0.0.0) by default.
Finding 3BTI-X07MCP-S-SHINZO-003

Telemetry opt-out only works with one exact string value

MEDIUM

The package allows turning off telemetry via an environment variable, but the check uses strict string equality with one specific value. Common variants buyers might try (true, yes, 1, disabled) all fail to disable telemetry. The opt-out works, but it's fragile in a way that increases the chance buyers think they've turned telemetry off when they haven't.

Evidence (2 references)
  • src/index.ts:74-79:
    function getConfig(config: any) {
      return {
        hubspotAccessToken: config?.HUBSPOT_ACCESS_TOKEN || process.env.HUBSPOT_ACCESS_TOKEN,
        telemetryEnabled: config?.TELEMETRY_ENABLED || process.env.TELEMETRY_ENABLED || "true"
      }
    }
    
    • src/index.ts:91if (telemetryEnabled !== "false") { ... } (strict string compare)
Finding 4BTI-X02MCP-S-SHINZO-004

Telemetry collector domain isn't the vendor's branded domain and isn't named in the privacy policy

LOW

Telemetry submissions go to a domain that doesn't match the vendor's stated brand domain in the README. The collector domain itself is also not named in the PRIVACY.md, so buyers reading the privacy policy can't readily identify where their telemetry data is going. Cited as a disclosure gap rather than a security finding.

Evidence (3 references)
  • src/index.ts:95exporterEndpoint: "https://api.otel.shinzo.tech/v1"
    • package.json:27 — author email at shinzolabs.com (different TLD)
    • PRIVACY.md:58 — "All data is sent securely via HTTPS to collectors controlled by Shinzo Labs or affiliate third parties (current infrastructure may be shared upon request)"
Finding 5BTI-M16aMCP-S-SHINZO-005

Production dependency tree carries 17 known vulnerabilities (2 critical, 5 high)

MEDIUM

The MCP's exact-pinned @modelcontextprotocol/sdk version is several releases behind the current one, and the resolved transitive dependency tree contains 17 known security advisories — 2 rated critical, 5 high, 10 medium-or-lower. Buyers in environments with vulnerability-management requirements (PCI-DSS, FedRAMP, internal supply-chain policies) will fail standard npm audit checks against the package.

Evidence (1 reference)

pnpm audit --prod output (run 2026-05-06):

  • Critical: protobufjs <7.5.5 (RCE), form-data <4.0.4 (unsafe random)
  • High: @modelcontextprotocol/sdk 1.12.3 — three advisories: ReDoS (patched in 1.25.2), cross-client data leak, missing input validation (patched in 1.24.0). The package pins exactly "@modelcontextprotocol/sdk": "1.12.3" (package.json:16); path-to-regexp ReDoS, lodash _.template code injection
  • Moderate: body-parser DoS, lodash prototype pollution, ajv ReDoS, qs arrayLimit bypass, path-to-regexp ReDoS, uuid buffer bounds, jsondiffpatch XSS
  • Most flow in via @opentelemetry/auto-instrumentations-node and @smithery/sdk transitive trees.
Also cites:BTI-M16b
Finding 6BTI-M05MCP-S-SHINZO-006

Telemetry samples every tool call with a 5-second metric export interval

LOW

By default, telemetry captures 100% of tool calls and exports metrics every 5 seconds — a high-volume, low-latency posture that's more aggressive than typical observability defaults. Buyers should weigh this against how often the LLM agent will exercise the MCP and how much usage metadata they're willing to send to the vendor's third-party collector.

Evidence (1 reference)
  • node_modules/@shinzolabs/instrumentation-mcp/dist/config.js:4-14:
    exports.DEFAULT_CONFIG = {
        samplingRate: 1.0, // 100% trace sampling by default
        metricExportIntervalMs: 5000,
        ...
    };
    
BTI-M Code Index

Codes Cited In This Profile

Each link goes to the BTI-M code reference page where you can see every MCP server in the corpus that triggered the same code.