Back to skill

Security audit

agent-governance

Security checks for vulnerabilities and agentic risk

Overview

This is a coherent governance-pattern skill, but several security-control examples are materially unsafe or misleading if copied into production.

Review this skill carefully before installing for production engineering work. Treat the code as conceptual only: replace the file path check with path-aware containment, make rate limits request-scoped, recursively validate structured arguments, and use non-overwriting or append-only audit storage before relying on these patterns for sensitive agents.

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

T05 · Unauthorized Access and Privilege Escalation

Error
Location
SKILL.md:503
Finding

Prefix-Based Path Validation Allows Reads Outside the Intended Root

Content
View full analysis
Remediation
View remediation
str: candidate = (TRUSTED_ROOT / path).resolve() if not candidate.is_relative_to(TRUSTED_ROOT): raise ValueError("Path traversal blocked by governance") if not candidate.is_file(): raise ValueError("Requested path is not a regular file") return candidate.read_text() ``` For Python versions without `Path.is_relative_to()`, use `os.path.commonpath()` and verify that the common path equals the trusted root. Additional hardening should include: - Rejecting absolute user-supplied paths if only workspace-relative paths are required. - Running the agent under a minimally privileged operating-system account. - Restricting access to symbolic links where the deployment threat model requires it. - Defining the trusted root in immutable application configuration rather than deriving it from the current working directory. - Adding regression tests for sibling-prefix paths, `..` components, absolute paths, and symbolic-link escapes. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
SKILL.md:221
Finding

Global Non-Resetting Counter Breaks Per-Request Rate Limiting

Content
View full analysis
policy.max_calls_per_request: raise PermissionError(f"Rate limit exceeded: {policy.max_calls_per_request} calls") ``` ### Technical Analysis The control is described as a per-request rate limit, but its counter is process-global, keyed only by the policy name, and never reset. Consequently, calls made by every request and user sharing a policy accumulate in the same counter. Once the cumulative count exceeds `max_calls_per_request`, all subsequent tool calls using that policy are denied until the process restarts or the global state is manually cleared. Concurrent requests may also race on shared state, depending on the execution environment. This implementation therefore fails to enforce the stated per-request boundary and introduces a persistent application-level denial-of-service condition. ### Attack Path 1. An attacker obtains access to any allowed tool governed by a policy shared with other users. 2. The attacker repeatedly invokes the tool. 3. Each invocation increments `_call_counters[policy.name]`, including successful calls from unrelated requests. 4. After the cumulative count exceeds `max_calls_per_request`, the decorator raises `PermissionError`. 5. Because no reset mechanism exists, later legitimate requests under the same policy continue to fail until the process is restarted or the state is cleared. ### Impact Assessment An attacker can deny governed tool functionality to all users and agents sharing the same policy name within the process. No operating-system privileges are gained, but service availability can be disrupted. The effect may persist across requests for the lif ...[truncated 88 chars]
Remediation
View remediation
policy.max_calls_per_request: raise PermissionError("Per-request tool-call limit exceeded") ``` ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
SKILL.md:244
Finding

Content Policy Checks Can Be Bypassed with Nested Tool Arguments

Content
View full analysis
Remediation
View remediation
max_depth: raise PermissionError("Argument nesting limit exceeded") if isinstance(value, str): yield value elif isinstance(value, Mapping): for key, item in value.items(): yield from iter_strings(key, depth + 1, max_depth) yield from iter_strings(item, depth + 1, max_depth) elif isinstance(value, (list, tuple, set, frozenset)): for item in value: yield from iter_strings(item, depth + 1, max_depth) elif is_dataclass(value): for field in fields(value): yield from iter_strings( getattr(value, field.name), depth + 1, max_depth ) for argument in [*args, *kwargs.values()]: for text in iter_strings(argument): matched = policy.check_content(text) if matched: raise PermissionError(f"Blocked pattern detected: {matched}") ``` Additional hardening should include: - Enforcing maximum nesting depth, input size, and collection length to prevent inspection-based denial of service. - Normalizing text where safe before matching. - Defining and validating strict schemas for every tool. - Failing closed for unsupported object types when the operation is sensitive. - Applying authorization at the action and resource level rather than relying solely on regular-expression content filters. - Adding tests for nested dictionaries, lists, model objects, encoded values, and mixed structured inputs. ]]>
Vulnerability Patterns
  • 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
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (1)

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The skill explicitly frames the audit log as append-only and immutable, but export_jsonl opens the target path with mode "w", which truncates any existing file before writing. In a governance/audit context, this can destroy prior audit history, undermine forensic integrity, and make compliance evidence unreliable if an operator or workflow re-exports to the same path.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.