Back to skill

Security audit

Agent Usage Tracker

Security checks for vulnerabilities and agentic risk

Overview

This skill is a coherent local usage-and-budget tracking package, with some dependency and input-validation issues users should address before relying on it for real spending controls.

Use this skill only where local SQLite storage of usage metadata is acceptable. Avoid putting secrets in the metadata field, choose the database path deliberately, pin dependencies with a lockfile, and fix the numeric validation before relying on the budget status to stop paid model usage.

Vulnerability Patterns
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (1)

T09 · Insecure Skill Coding Practices

Warning
Location
src/BudgetManager.ts:153
Finding

Non-Finite Numeric Values Can Bypass Budget Enforcement and Corrupt Usage Accounting

Content
View full analysis
1) { throw new Error("warningThreshold must be within (0, 1]."); } } ``` ```ts // src/CostCalculator.ts:12-17 setPricing(model: string, pricing: ModelPricing): void { if (pricing.inputCostPerMillion < 0 || pricing.outputCostPerMillion < 0) { throw new Error("Pricing values must be non-negative."); } this.pricing.set(model, pricing); } ``` ```ts // src/UsageTracker.ts:265-276 private validateUsage(input: UsageEventInput): void { if (!input.sessionId.trim()) { throw new Error("sessionId is required."); } if (!input.model.trim()) { throw new Error("model is required."); } if (input.promptTokens < 0 || input.completionTokens < 0) { throw new Error("Token counts must be non-negative."); } } ``` ### Technical Analysis The validation relies exclusively on relational comparisons. In JavaScript, comparisons involving `NaN` return `false`. Consequently, values such as `NaN` pass all of the following checks: - `NaN <= 0` - `NaN < 0` - `NaN > 1` The implementation also does not reject positive or negative infinity, fractional token counts, or integers beyond the safe integer range. The most security-relevant result occurs in budget evaluation: ```ts const usageRatio = spentUsd / policy.limitUsd; let status: BudgetEvaluation["status"] = "ok"; if (usageRatio >= 1) { status = "exceeded"; } else ...[truncated 2218 chars]
Remediation
View remediation
1 ) { throw new Error("warningThreshold must be a finite number within (0, 1]."); } ``` 2. Require token counts to be finite, non-negative safe integers: ```ts const validTokenCount = (value: number): boolean => Number.isFinite(value) && Number.isSafeInteger(value) && value >= 0; if ( !validTokenCount(input.promptTokens) || !validTokenCount(input.completionTokens) ) { throw new Error("Token counts must be non-negative safe integers."); } ``` 3. Validate pricing values before storing them: ```ts if ( !Number.isFinite(pricing.inputCostPerMillion) || !Number.isFinite(pricing.outputCostPerMillion) || pricing.inputCostPerMillion < 0 || pricing.outputCostPerMillion < 0 ) { throw new Error("Pricing values must be finite and non-negative."); } ``` 4. Validate calculated costs before inserting records. Reject non-finite or negative results returned by a custom `costCalculator`. 5. Make budget evaluation fail closed. If the limit, spend, or calculated ratio is non-finite, throw an error or return an explicit invalid-policy status rather than `"ok"`. 6. Add database-level constraints where practical, such as non-negative token and cost checks, to provide defense in depth. 7. Add tests covering: - `NaN` - `Infinity` and `-Infinity` - Fractional token counts - Values exceeding `Number.MAX_SAFE_INTEGER` - Non-finite custom calculator results - Invalid budget values producing an error rather than `"ok"` ]]>
Vulnerability Patterns
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (8)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
70% confidence
Finding

Without declared permissions the skill's intent is opaque and cannot be validated.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
91% confidence
Finding

The runtime dependency better-sqlite3 is specified with a caret range, which permits automatic installation of newer minor and patch releases. This weakens supply-chain reproducibility and can expose consumers to unexpected vulnerable or malicious upstream releases without a manifest change in this project.

Content

Scanner excerpt · package.json (reported line 23)May include surrounding context.

json
],
  "license": "MIT",
  "dependencies": {
    "better-sqlite3": "^11.8.1"
  },
  "devDependencies": {
    "@types/better-sqlite3": "^7.6.13",

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
86% confidence
Finding

The development dependency @types/better-sqlite3 is unpinned, so builds may resolve different package contents over time. While this is less risky than a runtime dependency, it still reduces build integrity and can introduce supply-chain issues in developer or CI environments.

Content

Scanner excerpt · package.json (reported line 26)May include surrounding context.

json
"better-sqlite3": "^11.8.1"
  },
  "devDependencies": {
    "@types/better-sqlite3": "^7.6.13",
    "@types/node": "^24.0.0",
    "tsx": "^4.19.3",
    "typescript": "^5.8.2",

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
86% confidence
Finding

The @types/node development dependency uses a caret range, allowing unreviewed upstream changes into developer and CI environments. Although it is not shipped at runtime, unpinned dev dependencies still weaken reproducibility and can contribute to supply-chain compromise risk.

Content

Scanner excerpt · package.json (reported line 27)May include surrounding context.

json
},
  "devDependencies": {
    "@types/better-sqlite3": "^7.6.13",
    "@types/node": "^24.0.0",
    "tsx": "^4.19.3",
    "typescript": "^5.8.2",
    "vitest": "^3.0.8"

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
86% confidence
Finding

The tsx development dependency is unpinned, so local and CI execution environments may consume different versions over time. Because tsx is an executable developer tool, a compromised or vulnerable upstream release could affect code execution during testing or examples.

Content

Scanner excerpt · package.json (reported line 28)May include surrounding context.

json
"devDependencies": {
    "@types/better-sqlite3": "^7.6.13",
    "@types/node": "^24.0.0",
    "tsx": "^4.19.3",
    "typescript": "^5.8.2",
    "vitest": "^3.0.8"
  }

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
85% confidence
Finding

The typescript dependency is specified as a version range, which allows compiler changes to enter the build without explicit review. This is primarily a build-chain integrity concern rather than a direct runtime flaw, but it still increases supply-chain and reproducibility risk.

Content

Scanner excerpt · package.json (reported line 29)May include surrounding context.

json
"@types/better-sqlite3": "^7.6.13",
    "@types/node": "^24.0.0",
    "tsx": "^4.19.3",
    "typescript": "^5.8.2",
    "vitest": "^3.0.8"
  }
}

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
93% confidence
Finding

The vitest dependency is unpinned, which means installs may resolve to different releases, including vulnerable ones. In this case the risk is amplified because vitest has known advisories and the manifest does not constrain resolution to a verified safe exact version.

Content

Scanner excerpt · package.json (reported line 30)May include surrounding context.

json
"@types/node": "^24.0.0",
    "tsx": "^4.19.3",
    "typescript": "^5.8.2",
    "vitest": "^3.0.8"
  }
}

Unverifiable Dependency: vitest has 3 known advisory(ies) (CVE-2026-47429 (When Vitest UI server is listening, arbitrary file can be read and executed); CVE-2026-84373 (Vitest: Path Traversal / Arbitrary File Read via @vitest/mocker Redirect Mock); CVE-2025-24964 (Vitest allows Remote Code Execution when accessing a malicious website while Vit)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
89% confidence
Finding

Vitest has known advisories affecting certain versions, including arbitrary file read and possible code execution scenarios, and this manifest does not pin an exact version to prove the installed release is unaffected. Because vitest is only a development dependency, the direct production impact is limited, but developer workstations and CI runners could still be exposed during testing.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.