Back to skill

Security audit

Claw Portfolio

Security checks for vulnerabilities and agentic risk

Overview

The skill is a coherent portfolio tracker, but its optional web UI exposes unauthenticated endpoints that can read and change locally stored financial records if reachable.

Review before installing. Use this only as a local personal tracker, do not expose the Next.js web UI to a network, and consider adding authentication, loopback binding, input schemas, CSV escaping, and dependency updates before relying on it for sensitive financial records. Price and dividend lookups send ticker symbols to Yahoo Finance and CoinGecko.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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)

T05 · Unauthorized Access and Privilege Escalation

Error
Location
src/app/api/portfolio/route.ts:17
Finding
Unauthenticated Portfolio Disclosure and Modification API<![CDATA[ ## Vulnerability Details **File Location**: `src/app/api/portfolio/route.ts:17-159` **Vulnerability Type**: Missing authentication and authorization **Risk Level**: High ### Vulnerable Code ```ts export async function GET() { const portfolio = getActivePortfolio(); const state = loadPortfolio(); const sellHistory = getSellHistory(); const realizedPL = sellHistory.reduce((sum, s) => sum + s.totalRealizedPL, 0); return NextResponse.json({ portfolio, portfolios: state.portfolios, activePortfolioId: state.activePortfolioId, realizedPL, sellHistory, }); } export async function POST(request: Request) { try { const body = await request.json(); if (body.action === 'createPortfolio') { const portfolio = createPortfolio(body.name); return NextResponse.json(portfolio, { status: 201 }); } if (body.action === 'setActive') { const portfolio = setActivePortfolio(body.id); if (!portfolio) { return NextResponse.json({ error: 'Portfolio not found' }, { status: 404 }); } return NextResponse.json(portfolio); } if (body.action === 'deletePortfolio') { const success = deletePortfolio(body.id); if (!success) { return NextResponse.json({ error: 'Cannot delete last portfolio' }, { status: 400 }); } return NextResponse.json({ success: true }); } // The remainder of this handler also processes sales and adds holdings // without authenticating or authorizing the caller. ``` ```ts export async function PUT(request: Request) { try { const { id, updates } = await request.json(); const holding = updateHolding(id, updates); if (!holding) { return NextResponse.json({ error: 'Holding not found' }, { status: 404 }); } return NextResponse.json(holding); } catch (error) { return NextResponse.json({ error: 'Failed to update holding' }, { status: 500 }); } } export async function DEL ...[truncated 3081 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Add authentication to every portfolio, dividend, price, and export API route. Reject unauthenticated requests with HTTP 401. 2. Add authorization checks that bind each portfolio and holding to an authenticated user. Do not rely only on possession of an object ID. 3. If the web UI is intended exclusively for local use, explicitly bind the production and development servers to loopback and document that restriction. Authentication should still be used if exposure is possible. 4. Add CSRF protection for state-changing requests. Validate `Origin` and `Host` headers and use SameSite cookies where cookie-based authentication is employed. 5. Define strict Zod schemas for each action and reject unknown properties. 6. Replace unrestricted `Partial<Holding>` updates with an allowlist of fields that users are permitted to modify. Never allow an update request to replace the holding ID. 7. Validate symbols, asset types, names, ISO dates, quantities, and prices. Require finite positive numeric values where appropriate and enforce reasonable string and collection limits. 8. Separate POST actions into dedicated endpoints or use a strict discriminated union so that missing or unknown actions cannot fall through to holding creation. 9. Add authorization-focused integration tests covering anonymous GET, POST, PUT, DELETE, and export requests. 10. Maintain backups or an append-only audit log for destructive portfolio operations. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
src/lib/storage.ts:139
Finding
Spreadsheet Formula Injection and Improper CSV Escaping<![CDATA[ ## Vulnerability Details **File Location**: `src/lib/storage.ts:139-149` **Vulnerability Type**: CSV injection and malformed CSV generation **Risk Level**: Medium ### Vulnerable Code ```ts export function exportToCsv(): string { const portfolio = getActivePortfolio(); const headers = ['Symbol', 'Name', 'Type', 'Quantity', 'Purchase Price', 'Purchase Date']; const rows = portfolio.holdings.map(h => [ h.symbol, h.name, h.type, h.quantity.toString(), h.purchasePrice.toString(), h.purchaseDate, ]); return [headers.join(','), ...rows.map(r => r.join(','))].join('\n'); } ``` The generated value is returned as a downloadable CSV by `src/app/api/export/route.ts:4-11`: ```ts export async function GET() { try { const csv = exportToCsv(); return new NextResponse(csv, { headers: { 'Content-Type': 'text/csv', 'Content-Disposition': 'attachment; filename="portfolio.csv"', }, }); } catch (error) { return NextResponse.json({ error: 'Failed to export CSV' }, { status: 500 }); } } ``` ### Technical Analysis User-controlled holding fields are concatenated with commas without CSV escaping. A value containing a comma, double quote, carriage return, or newline can alter the exported document's columns or inject additional rows. More importantly, spreadsheet applications may interpret cells beginning with characters such as `=`, `+`, `-`, or `@` as formulas. Because holding names and symbols can originate from API requests and are exported verbatim, an attacker can store a formula-like value and cause it to be included in the downloaded file. The risk is activated when a user opens the exported file in spreadsheet software that evaluates formulas. Depending on the spreadsheet application and its security configuration, an injected formula may trigger an external request, disclose data through a URL, display misleading content, or invoke other spreadsheet functionality. ### Attack ...[truncated 1538 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Replace manual string joining with a maintained CSV serialization library that implements RFC 4180 quoting and escaping. 2. Quote fields containing commas, double quotes, carriage returns, or newlines, and escape embedded double quotes by doubling them. 3. Neutralize spreadsheet formula prefixes in all text fields. If a cell begins with `=`, `+`, `-`, `@`, tab, carriage return, or another formula-triggering character, prefix it with a single quote or use a documented safe-text encoding appropriate for the target spreadsheet. 4. Apply formula neutralization after normalizing leading whitespace, because whitespace may be used to bypass simple first-character checks in some spreadsheet applications. 5. Validate and limit symbol and name lengths when holdings are created or updated. 6. Add tests for commas, quotes, CRLF sequences, embedded newlines, Unicode text, and all common spreadsheet formula prefixes. 7. Document that exported files contain untrusted user-provided data and should be opened with formula evaluation disabled where possible. ]]>
Vulnerability Patterns
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
Findings (59)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The declared description describes a financial portfolio tracking tool with substantial end-user functionality. The provided code chunk contains only a basic Next.js config file and does not implement any of the described capabilities. This is a material mismatch in primary purpose and behavior.

Tp4

High
Category
MCP Tool Poisoning
Confidence
81% confidence
Finding
The code clearly relates to portfolio tracking and does support multiple portfolios plus realized profit/loss from sell records, so it is partially aligned with the description. However, the declared purpose specifically presents a CLI with real-time prices and dividend tracking, while this code is an HTTP API route and contains no price-fetching or dividend functionality. It instead focuses on storage-backed CRUD operations for portfolios/holdings and sell transaction processing. That makes the description materially inaccurate for this code chunk.

Known Vulnerable Dependency: brace-expansion==2.0.2 — 4 advisory(ies): CVE-2026-13149 (brace-expansion: DoS via exponential-time expansion of consecutive non-expanding); CVE-2026-33750 (brace-expansion: Zero-step sequence causes process hang and memory exhaustion); CVE-2026-14257 (brace-expansion: DoS via unbounded expansion length causing an out-of-memory pro) +1 more

High
Category
Supply Chain
Confidence
93% confidence
Finding
brace-expansion 2.0.2 has multiple denial-of-service issues involving pathological brace patterns that can trigger excessive CPU or memory consumption. Although this instance is in a dev-tooling path under TypeScript/ESLint resolution, it can still be dangerous if CI, editor tooling, or automated checks process attacker-controlled glob patterns, potentially stalling builds or analysis jobs.

Known Vulnerable Dependency: minimatch==9.0.5 — 3 advisory(ies): CVE-2026-27904 (minimatch ReDoS: nested *() extglobs generate catastrophically backtracking regu); CVE-2026-26996 (minimatch has a ReDoS via repeated wildcards with non-matching literal in patter); CVE-2026-27903 (minimatch has ReDoS: matchOne() combinatorial backtracking via multiple non-adja)

High
Category
Supply Chain
Confidence
92% confidence
Finding
minimatch 9.0.5 is affected by ReDoS issues where crafted glob/extglob patterns can cause catastrophic backtracking and high CPU usage. In this skill, the package appears in development and linting/type-analysis paths rather than the runtime portfolio feature set, which lowers exposure but still leaves CI and developer workflows vulnerable if attacker-controlled patterns are evaluated.

Known Vulnerable Dependency: brace-expansion==1.1.12 — 4 advisory(ies): CVE-2026-13149 (brace-expansion: DoS via exponential-time expansion of consecutive non-expanding); CVE-2026-33750 (brace-expansion: Zero-step sequence causes process hang and memory exhaustion); CVE-2026-14257 (brace-expansion: DoS via unbounded expansion length causing an out-of-memory pro) +1 more

High
Category
Supply Chain
Confidence
94% confidence
Finding
brace-expansion 1.1.12 carries the same class of denial-of-service flaws as newer affected lines: crafted brace expressions can consume excessive CPU or memory and hang tooling. Even though this copy is transitive and likely limited to dev workflows, it remains a real vulnerability if untrusted patterns are ever processed during linting, builds, or path resolution.

Known Vulnerable Dependency: browserslist==4.28.1 — 2 advisory(ies): CVE-2026-73088 (Browserslist: Uncaught crash / prototype write via untrusted browserslist-stats.); CVE-2026-73089 (Browserslist: Unbounded memory growth (no cache eviction) via distinct query res)

High
Category
Supply Chain
Confidence
80% confidence
Finding
Dependency has known vulnerabilities (CVEs). Using packages with unpatched security flaws exposes the environment to known exploits.

Lp3

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding
The manifest declares no tool scope or permissions, yet the skill documentation explicitly states it performs network access for Yahoo Finance and CoinGecko queries. This creates an authorization and transparency gap: a consumer may treat the skill as local-only while it actually reaches external services, increasing privacy and policy risk.

Rp1

Medium
Category
MCP Rug Pull
Confidence
91% confidence
Finding
Using `npx tsx` without a pinned version allows execution to depend on whatever package version is resolved at runtime. This introduces supply-chain risk because a compromised or changed upstream package could execute unintended code when the skill is run.

Rp1

Medium
Category
MCP Rug Pull
Confidence
91% confidence
Finding
Using `npx tsx` without a pinned version allows execution to depend on whatever package version is resolved at runtime. This introduces supply-chain risk because a compromised or changed upstream package could execute unintended code when the skill is run.

Rp1

Medium
Category
MCP Rug Pull
Confidence
91% confidence
Finding
Using `npx tsx` without a pinned version allows execution to depend on whatever package version is resolved at runtime. This introduces supply-chain risk because a compromised or changed upstream package could execute unintended code when the skill is run.

Rp1

Medium
Category
MCP Rug Pull
Confidence
91% confidence
Finding
Using `npx tsx` without a pinned version allows execution to depend on whatever package version is resolved at runtime. This introduces supply-chain risk because a compromised or changed upstream package could execute unintended code when the skill is run.

Rp1

Medium
Category
MCP Rug Pull
Confidence
91% confidence
Finding
Using `npx tsx` without a pinned version allows execution to depend on whatever package version is resolved at runtime. This introduces supply-chain risk because a compromised or changed upstream package could execute unintended code when the skill is run.

Rp1

Medium
Category
MCP Rug Pull
Confidence
91% confidence
Finding
Using `npx tsx` without a pinned version allows execution to depend on whatever package version is resolved at runtime. This introduces supply-chain risk because a compromised or changed upstream package could execute unintended code when the skill is run.

Rp1

Medium
Category
MCP Rug Pull
Confidence
91% confidence
Finding
Using `npx tsx` without a pinned version allows execution to depend on whatever package version is resolved at runtime. This introduces supply-chain risk because a compromised or changed upstream package could execute unintended code when the skill is run.

Rp1

Medium
Category
MCP Rug Pull
Confidence
91% confidence
Finding
Using `npx tsx` without a pinned version allows execution to depend on whatever package version is resolved at runtime. This introduces supply-chain risk because a compromised or changed upstream package could execute unintended code when the skill is run.

Rp1

Medium
Category
MCP Rug Pull
Confidence
91% confidence
Finding
Using `npx tsx` without a pinned version allows execution to depend on whatever package version is resolved at runtime. This introduces supply-chain risk because a compromised or changed upstream package could execute unintended code when the skill is run.

Rp1

Medium
Category
MCP Rug Pull
Confidence
91% confidence
Finding
Using `npx tsx` without a pinned version allows execution to depend on whatever package version is resolved at runtime. This introduces supply-chain risk because a compromised or changed upstream package could execute unintended code when the skill is run.

Rp1

Medium
Category
MCP Rug Pull
Confidence
91% confidence
Finding
Using `npx tsx` without a pinned version allows execution to depend on whatever package version is resolved at runtime. This introduces supply-chain risk because a compromised or changed upstream package could execute unintended code when the skill is run.

Rp1

Medium
Category
MCP Rug Pull
Confidence
91% confidence
Finding
Using `npx tsx` without a pinned version allows execution to depend on whatever package version is resolved at runtime. This introduces supply-chain risk because a compromised or changed upstream package could execute unintended code when the skill is run.

Rp1

Medium
Category
MCP Rug Pull
Confidence
91% confidence
Finding
Using `npx tsx` without a pinned version allows execution to depend on whatever package version is resolved at runtime. This introduces supply-chain risk because a compromised or changed upstream package could execute unintended code when the skill is run.

Rp1

Medium
Category
MCP Rug Pull
Confidence
91% confidence
Finding
Using `npx tsx` without a pinned version allows execution to depend on whatever package version is resolved at runtime. This introduces supply-chain risk because a compromised or changed upstream package could execute unintended code when the skill is run.

Rp1

Medium
Category
MCP Rug Pull
Confidence
91% confidence
Finding
Using `npx tsx` without a pinned version allows execution to depend on whatever package version is resolved at runtime. This introduces supply-chain risk because a compromised or changed upstream package could execute unintended code when the skill is run.

Rp1

Medium
Category
MCP Rug Pull
Confidence
91% confidence
Finding
Using `npx tsx` without a pinned version allows execution to depend on whatever package version is resolved at runtime. This introduces supply-chain risk because a compromised or changed upstream package could execute unintended code when the skill is run.

Rp1

Medium
Category
MCP Rug Pull
Confidence
91% confidence
Finding
Using `npx tsx` without a pinned version allows execution to depend on whatever package version is resolved at runtime. This introduces supply-chain risk because a compromised or changed upstream package could execute unintended code when the skill is run.

Rp1

Medium
Category
MCP Rug Pull
Confidence
91% confidence
Finding
Using `npx tsx` without a pinned version allows execution to depend on whatever package version is resolved at runtime. This introduces supply-chain risk because a compromised or changed upstream package could execute unintended code when the skill is run.

Static analysis

No suspicious patterns detected.