Back to skill

Security audit

chitin-moat

Security checks for vulnerabilities and agentic risk

Overview

The skill is not overtly malicious, but it presents itself as enforcing high-impact agent permissions while only providing advisory instructions and incomplete config scripts.

Review before installing. This skill may be useful as a checklist or audit helper, but do not rely on it as a real security boundary for shell commands, file access, secrets, messaging, financial actions, or sub-agents unless you add separate authenticated identity checks and runtime enforcement outside the model instructions.

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
scripts/resolve_channel.py:11
Finding
Sovereign Access Is Granted Without Verifying the Configured Owner Identity<![CDATA[ ## Vulnerability Details **File Location**: `scripts/resolve_channel.py:11-41` **Related Location**: `references/example-config.yaml:7-16` **Vulnerability Type**: Authentication bypass in trust-level resolution **Risk Level**: High ### Vulnerable Code ```python def resolve(config_path: str, channel_id: str) -> dict: with open(config_path) as f: config = yaml.safe_load(f) # Check explicit channel matches for ch in config.get("channels", []): pattern = ch["id"] # Direct match or glob match if channel_id == pattern or fnmatch.fnmatch(channel_id, pattern): level = ch["level"] # Check overrides (for Discord-style server:channel patterns) # channel_id format: "discord:server_id:channel_name" or "discord:server_id" parts = channel_id.split(":") if len(parts) >= 3: channel_name = parts[-1] for ov in ch.get("overrides", []): if fnmatch.fnmatch(channel_name, ov["channel"]): return { "channel_id": channel_id, "level": ov["channel"], "resolved_level": ov["level"], "source": f"override '{ov['channel']}' in {pattern}", } return { "channel_id": channel_id, "resolved_level": level, "source": f"channel rule '{pattern}'", } ``` The example configuration declares an owner and associates that owner's channel with sovereign access: ```yaml # Owner identity — used to verify sovereign-level access owner: telegram: "REPLACE_WITH_YOUR_TELEGRAM_USER_ID" # Channel mappings channels: # Direct message with owner = full autonomy - id: "telegram:REPLACE_WITH_YOUR_TELEGRAM_USER_ID" level: sovereign ``` ### Technical Analysis The resolver loads the complete configuration but never ...[truncated 2076 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Accept authenticated platform and sender identity as separate, structured inputs instead of relying on a compound channel string. 2. For every sovereign result, require the authenticated sender identity to match the corresponding entry in `config["owner"]`. 3. Obtain identity attributes from a trusted messaging adapter or verified platform token, never from message text or another caller-controlled field. 4. Fail closed when identity evidence is missing, malformed, or unsupported. 5. Separate channel authorization from user authentication. A trusted channel must not automatically make every participant sovereign. 6. Restrict sovereign rules to exact matches and reject wildcard sovereign entries during validation. 7. Add tests demonstrating that: - A matching channel with the wrong sender is denied sovereign access. - A spoofed channel string does not grant sovereign access. - Missing authentication context resolves to a restrictive tier. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
SKILL.md:70
Finding
Documented Permission Boundaries Are Advisory and Lack Runtime Enforcement<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:70-82` **Related Location**: `SKILL.md:10-11` **Vulnerability Type**: Missing programmatic authorization enforcement **Risk Level**: High ### Vulnerable Code ```markdown ## Integration with AGENTS.md Add to the agent's workspace instructions: ```markdown ## Chitin Moat Before responding in any channel, resolve the trust level using `chitin-trust-channels.yaml`. Constrain capabilities to the resolved level. Never escalate beyond the channel ceiling. ``` ``` The Skill also describes its purpose as follows: ```markdown # Chitin Moat Enforce contextual agent permissions based on where a conversation happens. ``` ### Technical Analysis The project presents channel trust levels as enforced permission boundaries, but its integration mechanism consists only of natural-language instructions added to `AGENTS.md`. The supplied scripts validate configuration, print an audit summary, or return a trust-level label. They do not intercept or authorize shell execution, file access, secret access, messaging, financial operations, or sub-agent creation. Natural-language instructions are not a security boundary. An agent may fail to apply them consistently, lose relevant context, be affected by prompt injection, or invoke a tool through a path that does not consult the resolver. No fail-closed runtime control binds the resolved level to actual tool permissions. This creates a dangerous mismatch between the documented enforcement claim and the implementation. Operators may expose privileged tools believing they are constrained by the Skill when the controls remain voluntary. ### Attack Path 1. An operator installs the Skill and adds its recommended text to `AGENTS.md`. 2. The operator exposes privileged tools to the agent, relying on the documented trust matrix for protection. 3. An attacker sends a malicious or prompt-injection message from a guarded, observer, or otherwise restricted channel. 4. The age ...[truncated 1015 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Implement authorization at the tool dispatcher, API gateway, or capability broker rather than relying on model instructions. 2. Attach trusted channel and sender context to every tool invocation. 3. Resolve policy before execution and deny the operation when resolution fails or context is missing. 4. Translate each trust tier into an explicit capability allowlist enforced outside the model. 5. Prevent prompts and model output from modifying trusted identity or authorization context. 6. Ensure sub-agents inherit a non-escalating capability token from the parent request. 7. Log denied and allowed operations with the authenticated principal, channel, resolved tier, and policy rule. 8. Update the documentation to distinguish advisory guidance from technically enforced controls until runtime enforcement exists. 9. Add integration tests proving that prohibited tools cannot run from guarded, observer, or silent channels even when the model explicitly requests them. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/validate_config.py:40
Finding
Privileged Wildcard Rules and First-Match Shadowing Pass Configuration Validation<![CDATA[ ## Vulnerability Details **File Location**: `scripts/validate_config.py:40-61` **Related Location**: `scripts/resolve_channel.py:17-20` **Vulnerability Type**: Unsafe authorization-rule validation and precedence **Risk Level**: High ### Vulnerable Code The validator checks whether a configured level has a recognized name but does not restrict privileged wildcard patterns or detect overlapping rules: ```python # Validate channels channels = config.get("channels", []) if not isinstance(channels, list): errors.append("'channels' must be a list") else: for i, ch in enumerate(channels): if not isinstance(ch, dict): errors.append(f"channels[{i}]: must be a mapping") continue if "id" not in ch: errors.append(f"channels[{i}]: missing 'id'") if "level" not in ch: errors.append(f"channels[{i}]: missing 'level'") elif ch["level"] not in VALID_LEVELS: errors.append(f"channels[{i}]: invalid level '{ch['level']}' (valid: {VALID_LEVELS})") # Validate overrides for j, ov in enumerate(ch.get("overrides", [])): if "channel" not in ov: errors.append(f"channels[{i}].overrides[{j}]: missing 'channel'") if "level" not in ov: errors.append(f"channels[{i}].overrides[{j}]: missing 'level'") elif ov["level"] not in VALID_LEVELS: errors.append(f"channels[{i}].overrides[{j}]: invalid level '{ov['level']}'") ``` The resolver then accepts glob patterns and returns the first match: ```python for ch in config.get("channels", []): pattern = ch["id"] # Direct match or glob match if channel_id == pattern or fnmatch.fnmatch(channel_id, pattern): level = ch["level"] ``` ### Technical Analysis The validator only prohibits sovereign values in defaults. I ...[truncated 1908 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Reject wildcard patterns assigned to `sovereign`. 2. Require sovereign rules to use exact identifiers tied to a verified owner identity. 3. Reject or require explicit acknowledgement for broad `trusted` patterns. 4. Detect duplicate and overlapping channel rules during validation. 5. Replace first-match resolution with deterministic specificity ordering, where exact matches take precedence over globs and narrower patterns take precedence over broader patterns. 6. Fail validation when overlapping rules produce ambiguous or privilege-inverting outcomes. 7. Normalize and validate the platform-specific identifier structure before pattern matching. 8. Emit the effective precedence order during auditing. 9. Add regression tests covering broad privileged patterns, overlapping restrictive rules, duplicate patterns, and rule-order changes. ]]>
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • 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
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (3)

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding
The declared description emphasizes active enforcement of channel-based permission boundaries for AI agents and suggests a runtime security control system. The supplied code does not implement enforcement logic for exec, file I/O, secrets, or messaging access. Instead, it only audits an existing configuration file and prints a human-readable report with basic checks. While auditing channel permissions is mentioned in the description as a possible use case, the primary declared purpose is broader and centered on enforcement, which this code does not do. The file read is consistent with an audit utility, but it is still an undeclared capability given the empty declared permissions. Overall, the code materially underdelivers relative to the declared behavior and has a narrower, different primary function.

Credential Access

High
Category
Privilege Escalation
Content
|------------------------|-----------|------------|-------------|----------|--------|
| Execute shell commands | ✅        | ❌         | ❌          | ❌       | ❌     |
| Read/write files       | ✅        | ⚠️ scoped  | ❌          | ❌       | ❌     |
| Access secrets/env     | ✅        | ❌         | ❌          | ❌       | ❌     |
| Send external messages | ✅        | ⚠️ confirm | ❌          | ❌       | ❌     |
| Financial operations   | ✅        | ❌         | ❌          | ❌       | ❌     |
| Search/retrieve info   | ✅        | ✅         | ✅          | ❌       | ❌     |
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Intent-Code Divergence

Medium
Confidence
98% confidence
Finding
This is a true vulnerability: when an override matches, the function returns "level": ov["channel"] instead of returning the effective trust level in that field. Any downstream consumer that reads the returned "level" field rather than "resolved_level" may misinterpret a glob/channel pattern as the permission tier, causing incorrect enforcement or fallback behavior. In a skill whose purpose is to enforce channel-based trust boundaries, this kind of metadata corruption is especially dangerous because it can undermine the very access-control decision path protecting exec, file I/O, secrets, and messaging.

Static analysis

No suspicious patterns detected.