MCP Vendor Intelligence
Third-Party (Closed Source)Wraps HubSpot

@chinchillaenterprises/mcp-hubspot (npm)

by Chinchilla Enterprisesv3.3.2Updated 2025-07-11

A multi-tenant HubSpot MCP that markets credential persistence as the headline feature — store keys for multiple HubSpot accounts in your OS keychain, switch between them at runtime. The architecture works as advertised, but every disclosure layer around it is thin: no public source repo despite shipping the source code in the package, no SECURITY.md, no PRIVACY.md, ten months of stagnation since the last release, internal AI-orchestration documents accidentally shipped in the npm tarball, and the same architectural template recurs across at least six of this publisher's MCPs spanning different vendors. If you specifically need multi-account credential management for HubSpot, the feature works as advertised — but 10 months of stagnation with no security policy means nobody is watching for issues in the code that holds your credentials.

8 findings10 BTI-M codes
Max severity (buyer-facing)
MEDIUM

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. Chinchilla Enterprises — a single publisher. Published as @chinchillaenterprises/mcp-hubspot on npm, version 3.3.2, last updated July 2025.

What it does. Provides 17 MCP tools across 6 categories: account management (7), contacts (4), tasks (3), associations (1), properties (create-only), and email templates (create-only). The headline feature is multi-tenant credential storage: persist HubSpot tokens for production, sandbox, and client accounts in your OS keychain, then switch between them at runtime without restarting the MCP.

What it collects. A HubSpot access token per account you configure. On first run, any token already set in the HUBSPOT_ACCESS_TOKEN environment variable is silently migrated into your OS keychain for persistence. The migration is one-way — the keychain becomes the source of truth from then on.

What it stores. HubSpot tokens in your OS keychain (macOS Keychain, Windows Credential Manager, or Linux Secret Service). When the keychain isn't available, the package falls back to an encrypted file in your home directory — but the encryption key for that fallback is stored alongside the encrypted file, which means the encryption protects against backup leaks but not against any attacker who already has filesystem access to your home directory.

Where data goes. HubSpot's API at https://api.hubapi.com. No third-party telemetry. No analytics SDK. The package itself ships with internal AI-orchestration documents from the publisher's development process (AGENT1_REPORT.md through AGENT6_REPORT.md, AGENT_TASKS.md, REFACTOR_REQUIREMENTS.md) accidentally included in the npm tarball — a build-hygiene gap rather than a security finding, but indicative of the package's overall packaging discipline.

Findings

8 Findings

10 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.

Pattern 8BTI-M14MCP-S-CHINCHILLA-008

Same architectural template recurs across the publisher's other MCP packages

MEDIUM

The credential-manager and account-state code in this package isn't unique to HubSpot — the same template ships across at least six of the publisher's MCP packages, spanning HubSpot, Stripe, Slack, and other vendors. Buyers evaluating one Chinchilla MCP are implicitly evaluating the same architecture across the rest of the publisher's portfolio. Cited as a cross-package pattern because the architectural choices documented above generalize, for better or worse, to the publisher's overall MCP strategy.

Exploit precondition
None — this is a publisher-posture observation, not an attack chain
Evidence (0 references)
  • feathars91 publishes 28 packages under @chinchillaenterprises scope
    • At least 5 sampled siblings ship the same keytar-based credential-manager pattern: mcp-confluence, mcp-jira, mcp-stripe, mcp-amplify each have a credential-manager.js file (5 file matches each); mcp-slack uses keytar inline in dist/index.js (different code structure, same library)
    • mcp-google-drive lists keytar as a dep but uses a different implementation
    • At least 6 packages ship "multi-tenant + credential persistence" architecture per their npm descriptions
Finding 1BTI-M03MCP-S-CHINCHILLA-001

Silent migration of `HUBSPOT_ACCESS_TOKEN` env var to OS keychain on first run, with no notification

MEDIUM

On first run, if you have HUBSPOT_ACCESS_TOKEN set in your environment, the package silently moves it into your OS keychain (or the encrypted-file fallback) and uses the persisted credential for every subsequent run. There's no startup banner, no log line, no opt-out. After this migration, the environment variable is no longer consulted — the keychain is the source of truth. If you later rotate your HubSpot token without using the package's update_account tool, or uninstall the package without using remove_account, a stale credential can remain in your keychain indefinitely.

Exploit precondition
None — fires under documented usage on every first run with a legacy env var set
Evidence (2 references)
  • dist/services/account-state.js:62-77 (initializeFromEnvironment):

    if (process.env.HUBSPOT_ACCESS_TOKEN && this.state.accounts.size === 0) {
        const legacyAccount = {
            id: 'env-legacy',
            name: 'Environment Account',
            accessToken: process.env.HUBSPOT_ACCESS_TOKEN,
            portalId: process.env.HUBSPOT_PORTAL_ID,
            isDefault: true
        };
        this.state.accounts.set(legacyAccount.id, legacyAccount);
        this.state.activeAccountId = legacyAccount.id;
        await this.createClient(legacyAccount);
        await this.credentialManager.saveAccount(legacyAccount);  // <-- writes to keychain or encrypted file
        await this.credentialManager.setActiveAccountId(legacyAccount.id);
    }
    
    • dist/services/credential-manager.js:90-110saveAccount calls keytar.setPassword(SERVICE_NAME='mcp-hubspot', 'hubspot-env-legacy', JSON.stringify(persistedAccount)). The token is now in the macOS Keychain Access (or equivalent) under the service name mcp-hubspot, account name hubspot-env-legacy.
    • No console.error line in account-state.js warns the user that this migration happened. The credential-manager does log Account env-legacy saved to keychain to stderr — but stderr is typically not surfaced to the user by MCP clients (it goes to the client's log file, not the conversation).
    • README §Migration documents the migration but does not specify: (a) the migration runs silently with no user prompt; (b) once migrated, the env var is no longer the source of truth — the keychain is; (c) the only way to remove the persisted credential is via the remove_account MCP tool with accountId: 'env-legacy' or by manually editing the OS keychain.
Also cites:BTI-M04
Finding 2BTI-M07MCP-S-CHINCHILLA-002

Six internal AI-orchestration documents were accidentally shipped in the npm package

LOW

The published npm tarball contains AGENT1_REPORT.md through AGENT6_REPORT.md, plus AGENT_TASKS.md and REFACTOR_REQUIREMENTS.md — internal documents from the publisher's development process. None of them contain credentials, but they reveal more about the publisher's development workflow than the publisher likely intended. Build-hygiene observation rather than a security finding, but it's the kind of detail that signals overall packaging discipline.

Exploit precondition
None
Evidence (0 references)
  • Tarball file listing shows: AGENT1_REPORT.md, AGENT2_REPORT.md, AGENT3_REPORT.md, AGENT4_REPORT.md, AGENT5_REPORT.md, AGENT6_REPORT.md, AGENT_TASKS.md, REFACTOR_REQUIREMENTS.md — all in tarball root
    • These are internal AI-orchestrated refactor task specifications and completion reports. Sample from AGENT_TASKS.md: "Sub-Agent Task Specifications... Agent 1: Types & Schemas Architect... Agent 2: Services Engineer..." Each AGENT_REPORT.md is a "what I built" summary written by an AI agent.
    • package.json has no files field, so npm packages everything not in .gitignore.
    • No .npmignore in repo root.
    • Net effect: a multi-agent Claude/AI-orchestrated refactor workflow that converted a "1,822-line monolithic src/index.ts" into the current modular structure left its task-specification and completion-report artifacts in the published package.
Finding 3BTI-M09bMCP-S-CHINCHILLA-003

No public source repository, despite the source code shipping in the package

MEDIUM

The package's TypeScript source ships in the npm tarball, so the code is auditable from the package itself. There's no public GitHub repository, however, where you could review commit history, file an issue, see how known issues are being handled, or assess the publisher's response time to security disclosures. Buyers used to evaluating an open-source MCP via its public repo find that path closed here.

Exploit precondition
None — this is a governance-posture observation, not an attack vector
Evidence (0 references)
  • package.json has no repository field
    • GitHub search for "chinchilla enterprises hubspot mcp" returns 0 results
    • npm metadata records gitHead: 84441d6209807979cc3d7f0584c3f094cd63d655 — suggesting the source DOES exist in some git repo, just not a publicly-discoverable one
    • The src/ TypeScript IS shipped in the tarball (full readable source). This makes the package source-on-disk but not source-controlled-publicly.
Finding 4BTI-X09MCP-S-CHINCHILLA-004

Encrypted-file fallback stores the encryption key next to the encrypted file

LOW

When the OS keychain isn't available, the package encrypts your HubSpot tokens with AES-256-CBC and writes them to disk in your home directory. The key used for that encryption is also stored on disk in the same directory. This protects against someone reading the encrypted file in isolation (e.g., from a backup), but doesn't protect against any attacker who already has filesystem read access to your home directory — they have both the file and the key.

Exploit precondition
Local read access to ~/.mcp-hubspot/ (i.e., already-compromised user account on the same machine)
Evidence (1 reference)
  • dist/services/credential-manager.js:11-13:

    CONFIG_DIR = path.join(os.homedir(), '.mcp-hubspot');
    CONFIG_FILE = path.join(this.CONFIG_DIR, 'accounts.json');
    ENCRYPTION_KEY_FILE = path.join(this.CONFIG_DIR, '.key');
    
    • Both files have chmod 0600 (read/write owner only) and live in a chmod 0700 directory.
    • crypto.createCipheriv('aes-256-cbc', this.encryptionKey, iv) with random per-record IV.
Finding 5BTI-M11MCP-S-CHINCHILLA-005

Properties and Email Templates expose only `create_*` tools, not the full CRUD the README implies

LOW

The README lists Properties and Email Templates among the supported HubSpot resources, suggesting a complete tool set. The actual implementation only includes create_* tools — there's no read, update, or delete for either resource. Buyers planning workflows that need to read or modify existing properties or templates will need to fall back to a different MCP.

Exploit precondition
None
Evidence (0 references)
  • README §Property Management lists 5 sub-features (create, configure options, groups, advanced settings, etc.) but only dist/tools/property/create-property.js exists — no get-property, update-property, list-properties, or delete-property.
    • README §Email Template Management lists 5 sub-features but only dist/tools/email-template/create-email-template.js exists.
    • Compare to other categories: contacts have create/get/search/update; tasks have create/get/update; accounts have full CRUD-plus.
Also cites:BTI-X04
Finding 6BTI-M10MCP-S-CHINCHILLA-006

Ten months without a release — version 3.3.2 has been current since July 2025

MEDIUM

The package's last release was version 3.3.2 in July 2025; nothing has been published since. There's no public roadmap, no public issue tracker (Finding 3), and no statement from the publisher about future releases. Buyers should treat this as a frozen artifact rather than an actively maintained one.

Exploit precondition
None — process risk
Evidence (0 references)
  • npm view @chinchillaenterprises/mcp-hubspot time — 15 versions published 2025-06-26 through 2025-07-11; nothing since.
    • @modelcontextprotocol/sdk: ^1.12.3 — caret range will pull latest patches at install time, but the published behavior of the package itself is frozen.
Finding 7BTI-X12MCP-S-CHINCHILLA-007

No SECURITY.md, no PRIVACY.md, no credential-purge guidance

MEDIUM

The package ships with no documented vulnerability disclosure process, no privacy policy, and no documented procedure for purging stored credentials when uninstalling. Combined with Finding 1 (silent migration to keychain) and Finding 3 (no public repo), buyers have no path for raising a security concern or understanding what the publisher's process is for handling one.

Exploit precondition
None
Evidence (0 references)

No SECURITY.md, no PRIVACY.md, no CHANGELOG.md in the published artifact. README does document the remove_account MCP tool but does not include OS-level guidance like "to fully remove the credential, also run keytar's deletion utility or check Keychain Access.app for entries under service name mcp-hubspot."

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.