Back to skill

Security audit

Bot Police

Security checks for vulnerabilities and agentic risk

Overview

This defensive bot-triage skill is mostly coherent, but it needs review because it can direct quarantine-style actions without clear user-control boundaries and its scoring can be manipulated by malformed telemetry.

Install only where bot restriction or quarantine actions are clearly scoped and preferably require human approval. Treat its output as advisory unless upstream telemetry is schema-validated and trusted, since malformed records can bypass or interrupt its scoring.

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 (2)

T09 · Insecure Skill Coding Practices

Error
Location
index.js:27
Finding
Negative telemetry values allow risk-score manipulation and detection bypass<![CDATA[ ## Vulnerability Details **File Location**: `index.js`, lines 27-29 and 51-58 **Vulnerability Type**: Improper input validation and risk-score manipulation **Risk Level**: High ### Complete Code Snippet ```js const trustScore = Number.isFinite(bot.trustScore) ? bot.trustScore : 50; const incidents = Number.isFinite(bot.incidents) ? bot.incidents : 0; const anomalyCount = Number.isFinite(bot.anomalyCount) ? bot.anomalyCount : 0; // ... score += incidents * 8; score += anomalyCount * 5; if (trustScore < 50) score += Math.min(25, 50 - trustScore); let action = 'allow'; if (score >= 80) action = 'quarantine'; else if (score >= 50) action = 'block'; else if (score >= 25) action = 'watch'; ``` ### Technical Analysis The implementation checks whether `incidents` and `anomalyCount` are finite numbers but does not enforce non-negative values or reasonable upper bounds. Both fields are added directly to the risk score. Consequently, negative values subtract points from the score. A sufficiently negative value can offset any combination of hostile indicators, including data-exfiltration signals, privilege escalation, identity spoofing, and quarantine-bypass attempts. For example, a record with `quarantineBypass: true` receives 40 risk points, but setting `incidents: -100` subtracts 800 points. The resulting score remains below the `watch` threshold, causing the skill to return `allow`. The weak top-level validator at `index.js:72-73` does not prevent this condition because it validates only that the input is an object: ```js async validate(input) { return !input || typeof input === 'object'; } ``` ### Attack Path 1. An attacker gains control over, or can influence, a bot telemetry record submitted to the skill. 2. The attacker includes one or more genuine hostile indicators, such as `quarantineBypass: true` or `exfiltrationSignals: 1`. 3. The attacker supplies a large negative finite value for `incidents` or `anomalyCount`. 4. `evaluateBot()` mult ...[truncated 1092 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Require `incidents` and `anomalyCount` to be non-negative integers. - Apply documented upper bounds to prevent unrealistic values and numeric abuse. - Constrain `trustScore` to its intended range, such as 0 through 100. - Reject malformed telemetry instead of silently substituting defaults for security-sensitive fields. - Add schema validation before evaluating any bot record. - Consider clamping the final risk score to a documented range. - Add tests proving that negative, fractional, excessively large, and incorrectly typed values are rejected. Example hardening: ```js const isBoundedInteger = (value, min, max) => Number.isInteger(value) && value >= min && value <= max; if (!isBoundedInteger(bot.incidents, 0, 10000)) { throw new TypeError('incidents must be an integer between 0 and 10000'); } if (!isBoundedInteger(bot.anomalyCount, 0, 10000)) { throw new TypeError('anomalyCount must be an integer between 0 and 10000'); } if (!Number.isFinite(bot.trustScore) || bot.trustScore < 0 || bot.trustScore > 100) { throw new TypeError('trustScore must be a finite number between 0 and 100'); } ``` ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
index.js:11
Finding
Malformed bot entries can terminate an entire batch scan<![CDATA[ ## Vulnerability Details **File Location**: `index.js`, lines 11 and 26 **Vulnerability Type**: Improper element validation causing denial of service **Risk Level**: Medium ### Complete Code Snippet ```js async execute(input = {}) { const bots = Array.isArray(input.bots) ? input.bots : []; const suspects = bots.map((bot, index) => this.evaluateBot(bot, index)); const flagged = suspects.filter(bot => bot.action !== 'allow'); return { success: true, scanned: suspects.length, flaggedCount: flagged.length, flagged, summary: { allow: suspects.filter(bot => bot.action === 'allow').length, watch: suspects.filter(bot => bot.action === 'watch').length, block: suspects.filter(bot => bot.action === 'block').length, quarantine: suspects.filter(bot => bot.action === 'quarantine').length } }; }, evaluateBot(bot, index) { const id = bot.id || bot.name || `bot-${index + 1}`; ``` ### Technical Analysis `execute()` confirms only that `input.bots` is an array. It does not verify that each array element is a non-null object before passing it to `evaluateBot()`. If an element is `null` or `undefined`, the expression `bot.id` throws a `TypeError`. Because `Array.prototype.map()` is executed without per-record error handling, one invalid entry aborts processing of the entire batch. Valid records appearing before or after the malformed item do not receive a completed report. The validator at `index.js:72-73` also accepts malformed structures, including arrays and objects containing invalid bot entries: ```js async validate(input) { return !input || typeof input === 'object'; } ``` ### Attack Path 1. An attacker submits or injects a malformed element into the `bots` array. 2. `execute()` accepts the array because `Array.isArray(input.bots)` returns `true`. 3. The array element is passed to `evaluateBot()`. 4. For a `null` element, evaluating `bot.id` raises a `TypeError`. 5. The exception terminates the ...[truncated 859 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Validate that every `bots` entry is a non-null plain object before evaluation. - Reject the complete request with a structured validation error when strict atomic processing is required. - Alternatively, isolate errors per record and return an explicit invalid-record result so one malformed entry cannot terminate the batch. - Update `validate()` to enforce the complete input schema rather than checking only `typeof input`. - Add tests for `null`, `undefined`, primitive values, arrays nested as entries, and objects with invalid fields. Example strict validation: ```js async validate(input) { if (input === undefined) return true; if (input === null || typeof input !== 'object' || Array.isArray(input)) { return false; } if (input.bots !== undefined && !Array.isArray(input.bots)) { return false; } return (input.bots || []).every(bot => bot !== null && typeof bot === 'object' && !Array.isArray(bot) ); } ``` For fault-isolated processing, validate each record before calling `evaluateBot()` and return a structured error containing the element index without exposing internal stack traces. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep

Static analysis

No suspicious patterns detected.