Back to skill

Security audit

fulcra-dashboard

Security checks for vulnerabilities and agentic risk

Overview

This skill appears intended to build a Fulcra dashboard, but it has real review-worthy risks around private data, public publishing, remote dependencies, and unsafe HTML rendering.

Install only if you are comfortable reviewing exactly which Fulcra records are copied into public/ before sharing. Prefer local-only use, vendor or pin browser libraries, avoid publishing sensitive timelines, and fix the x-html/formatValue rendering issue before deploying a dashboard publicly.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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 (2)

T09 · Insecure Skill Coding Practices

Error
Location
template-dashboard/public/app.js:114
Finding

Stored Cross-Site Scripting Through Unsanitized Fulcra Record Values

Content
View full analysis
${label}`; } } return textStr; } // Fallback for primitive values return d.value; } ``` The returned value is rendered through an HTML interpretation sink: ```html ``` ### Technical Analysis Timeline records are read from JSONL files and passed to `formatValue()`. Both `d.value` and the metadata-derived `label` can originate from downloaded Fulcra records. The function concatenates these values into an HTML string without escaping or sanitization. The dashboard then uses Alpine.js `x-html`, which assigns interpreted HTML rather than text. Consequently, a malicious record value such as an element with an event handler can introduce executable browser content. The fallback path is also vulnerable because it returns `d.value` directly to the same HTML sink. This is a stored XSS condition because ...[truncated 1485 chars]
Remediation
View remediation
``` 2. Do not use HTML entities or tags in `formatValue()`. Return plain text instead: ```javascript formatValue(d) { if (d.value === undefined || d.value === null) return ''; if ( d.metadata?.measurement_spec?.measurement_type === 'scale' ) { const maxVal = d.metadata.measurement_spec.scale?.max_allowed || 5; let result = `${String(d.value)}/${String(maxVal)}`; const mapping = d.metadata?.spec?.scale?.label_mapping?.string?.mapping; const label = mapping?.[String(d.value)]; if (label) { result += ` — ${String(label)}`; } return result; } return String(d.value); } ``` 3. If emphasized formatting is required, render the value and label in separate elements, each using `x-text`, instead of assembling HTML. 4. If arbitrary HTML is an unavoidable product requirement, sanitize it with a pinned, audited sanitizer and a strict element-and-attribute allowlist before passing it to `x-html`. 5. Add a restrictive Content Security Policy as defense in depth. Avoid permitting inline scripts or event handlers. 6. Add tests using payloads containing elements, event handlers, malformed tags, SVG content, and encoded markup to verify that all record fields are rendered only as text. ]]>

T08 · Insecure Dependencies

Warning
Location
template-dashboard/public/index.html:9
Finding

Mutable and Unverified Third-Party Dependencies

Content
View full analysis
``` The Skill also recommends unpinned global package installations: ```bash npm install -g surge ``` ```bash npm i -g vercel ``` The Python visualization script recommends unpinned dependencies: ```text Requirements: pip install wordcloud matplotlib ``` ```python except ImportError: print("Error: Missing required packages. Run: pip install wordcloud matplotlib") sys.exit(1) ``` ### Technical Analysis The Alpine.js URL uses the mutable `3.x.x` selector, while the D3 URL uses a mutable major-version alias. Neither script tag specifies an SRI hash. The effective browser code can therefore change after the Skill has been audited without any corresponding change to the project. The npm and pip installation commands similarly resolve whatever package versions are current at installation time. The npm tools are installed globally, increasing their execution scope and making them available outside this project. This creates a supply-chain trust boundary in which code from external CDNs and package registries executes without a reproducible version or cryptographic integrity check. ### Attack Path 1. A CDN, package registry, maintainer account, or upstream release channel is compromised, or a mutable dependency receives a malicious or incompatible release. 2. The dashboard loads the changed Alpine.js or D3 asset, or the user executes one of the unpinned package-ins ...[truncated 1014 chars]
Remediation
View remediation
``` 3. Prefer self-hosting reviewed Alpine.js and D3 assets under `public/assets/` so the deployed dashboard does not execute mutable third-party code. 4. Pin exact npm and Python package versions and maintain lockfiles or hash-checked requirements. 5. Avoid global npm installations. Use project-local, version-pinned execution where possible. 6. Use Python hash verification, such as a requirements file with exact versions and `--require-hashes`. 7. Audit deployment and visualization dependencies before upgrades, and use automated dependency scanning. 8. Apply a restrictive Content Security Policy that limits `script-src` and network destinations to explicitly approved origins. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (17)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

A substantial description-behavior mismatch makes it harder for users and enforcement systems to understand what the skill actually does, which is dangerous for a skill handling private data and publication workflows. When declared behavior understates or misstates actual actions, reviewers may approve a capability set that is broader or riskier than intended.

Content

No source excerpt is available for this finding.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
- `app.js` (Alpine `Alpine.data()` and D3 functions)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
96% confidence
Finding

The skill directs network access, local file operations, and environment-dependent execution but does not declare any explicit tool scope or permission boundaries. In an agent setting, this increases the chance of overbroad capability use, especially because the skill also handles private Fulcra data and later discusses public deployment workflows.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The skill introduces public publishing very early without an equally prominent upfront privacy warning, despite working with private Fulcra data. Even though later sections add confirmation steps, deferring the warning increases the risk that users normalize the idea of publishing before fully appreciating that sensitive personal records may be involved.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The skill explicitly authorizes fallback to an external rapid-UI service and other external tools, which can transfer private user data outside the local dashboard environment described in the manifest. In context, this is risky because the skill's core dataset is the user's private Fulcra store, so externalizing even summaries or structured records expands the trust boundary significantly.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The trigger guidance includes broad natural-language phrases like "set up the web app" and "create a dashboard for the Fulcra skills," which could overlap with ordinary requests outside this specific skill. The file does not provide negative examples or tighter scope constraints to distinguish when this skill should activate versus other web-app or dashboard-related skills.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
93% confidence
Finding

The unpinned invocation uv tool run fulcra-api allows the resolved tool version to change over time, which can alter behavior or introduce a compromised dependency into a workflow that accesses private user data. Because the skill uses this tool for data discovery and ingestion, supply-chain drift directly affects confidentiality and integrity.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
93% confidence
Finding

This use of uv tool run fulcra-api is unpinned in a step that catalogs user data, so a changed or malicious upstream version could enumerate or process data differently than reviewed. Since the command influences which private records are selected, the risk is not only reliability but also unintended data exposure.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
94% confidence
Finding

The unpinned fulcra-api get-records command fetches sensitive records and writes them to local files, so any upstream change in the fetched tool could exfiltrate data, over-collect data, or produce unsafe output. The danger is elevated by the skill's later guidance to copy approved files into a publishable directory.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
94% confidence
Finding

The unpinned data-updates invocation is part of a required pipeline that moves output into public/, creating a path from external tool execution to publishable artifacts. If the tool version changes unexpectedly, it could generate misleading or privacy-sensitive output that is later exposed to the user or the public.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

Requiring an external image generation tool introduces unnecessary data-sharing and dependency risk that is not essential to building a local dashboard. Because the prompt generation may incorporate user theme, activity summaries, or other contextual details, it can leak sensitive information to a third-party service without a strong functional need.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The manifest frames sharing as export of a previewable directory, but the instructions go further and direct direct deployment to public hosting providers. That expands the operational risk from local file preparation to internet publication of user data, and users may not realize the skill includes full deployment behavior when invoking it.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The manifest frames this skill as building a local dashboard for private Fulcra data and exporting a previewable directory for sharing. This file adds a 3D Plotly visualization helper whose inline documentation explicitly instructs injecting a remote CDN script, which is not an obvious requirement for a local private dashboard and would introduce third-party network dependency if used.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The page loads Alpine.js and D3 from third-party CDNs, which means a dashboard intended to display private local Fulcra data executes remote JavaScript in the same origin and context as that sensitive data. If the CDN content is compromised, swapped, or observed through network controls, an attacker could run arbitrary code in the dashboard and exfiltrate private records from the locally viewed/exported dataset.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The stylesheet imports Google Fonts from a third-party domain, which causes browsers viewing the dashboard to make outbound requests and disclose client metadata such as IP address, user agent, and access timing. In a skill explicitly described as operating on private Fulcra data locally and producing shareable static exports, this undermines the local-only privacy expectation and can create avoidable external network dependencies.

Content

No source excerpt is available for this finding.

Scope Creep

Low
Category
Excessive Agency
Confidence
70% confidence
Finding

Skill's behavior or capabilities extend beyond its stated purpose. Scope creep allows an agent to perform actions unrelated to its documented functionality, increasing the attack surface.

Content

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

md
- **High-Fidelity Goal:** If the user is specifically trying to build a high-quality dashboard, you should spend more time troubleshooting and trying to make the static triad, localhost server, or public deployment work.
- **Fast Visibility (e.g., Onboarding):** If the user is just trying to view things for the first time (such as during the `fulcra-get-started` flow), give faster delivery more weight.

If the primary static triad and deployment routes are truly not viable in the current environment, you must gracefully fall back to alternative delivery mechanisms. Alternative options include (but are not limited to):
- **Prefab (`https://gofastmcp.com/apps/prefab`):** Using an external rapid-UI generator if configured.
- **Custom HTML/Image Generation:** Generating a simpler bespoke HTML file or using Python (e.g., `matplotlib`) to render a static image chart summarizing the data.
- **ASCII Charts & Markdown:** As a last resort, or for extremely fast inline updates, render the data directly in the chat using Markdown tables and ASCII visualizations.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
91% confidence
Finding

Loading fonts from fonts.googleapis.com leaks viewer metadata to Google without an in-product warning or consent mechanism. While this is not direct code execution, it is still a privacy issue, especially because the dashboard is meant to present private data locally and may be assumed to avoid third-party calls.

Content

No source excerpt is available for this finding.