Back to skill

Security audit

Isolated Multi-Agent Control Plane

Security checks for vulnerabilities and agentic risk

Overview

This skill installs a local multi-agent control-plane blueprint, but its included tools do not reliably enforce the security boundaries and audit controls they promise.

Treat this as a prototype, not a secure production control plane. Install only in an isolated test directory or account, and do not rely on it for agent isolation, approval enforcement, mailbox integrity, or audit records until message ID validation, authenticated actor binding, filesystem permissions, log initialization, and pre-mutation integrity checks are added.

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

T09 · Insecure Skill Coding Practices

Error
Location
assets/blueprint/scripts/mailboxctl.py:69
Finding

Mailbox Message ID Allows Path Traversal Outside the Mailbox

Content
View full analysis
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Error
Location
assets/blueprint/scripts/mailboxctl.py:118
Finding

Caller-Supplied Role Names Allow Team Lead and Receiver Impersonation

Content
View full analysis
{nxt}') actor = a.actor # Receiver can ACK/RESOLVED/REJECTED for their message; Team Lead can arbitrate any if actor != 'team-lead' and actor != h.get('receiver'): raise SystemExit('only receiver or team-lead can update status') h['status'] = nxt h['timestamp'] = now_iso() if a.increment_retry: h['retry_count'] = int(h.get('retry_count', 0)) + 1 if a.note: b = b + f"\n## Response ({actor})\n\n{a.note}\n" h['checksum'] = checksum_for(h, b) with open(p, 'w', encoding='utf-8') as f: f.write(render_message(h, b)) event({'ts': now_iso(), 'type': 'mail_status', 'message_id': h['message_id'], 'task_id': h['task_id'], 'from': cur, 'to': nxt, 'actor': actor}) ``` ```python def cmd_gc(a): ensure_dirs() if a.actor != 'team-lead': raise SystemExit('only team-lead can run mailbox GC') statuses = set([x.strip() for x in a.statuses.split(',') if x.strip()]) moved = 0 files = sorted([f for f in os.listdir(MAILBOX) if f.endswith('.md')]) for fn in files: src = os.path.join(MAILBOX, fn) h, _ = parse_message(src) st = h.get('status') if st in statuses: dst = os.path.join(ARCHIVE, fn) os.replace(src, dst) moved += 1 event({'ts': now_iso(), 'type': 'mail_gc', 'message_id': h.get('message_id'), 'task_id': h.get('task_id'), 'status': st, ...[truncated 2241 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
assets/blueprint/scripts/mailboxctl.py:109
Finding

Status Updates Re-Sign Previously Tampered Mailbox Messages

Content
View full analysis
{nxt}') actor = a.actor if actor != 'team-lead' and actor != h.get('receiver'): raise SystemExit('only receiver or team-lead can update status') h['status'] = nxt h['timestamp'] = now_iso() if a.increment_retry: h['retry_count'] = int(h.get('retry_count', 0)) + 1 if a.note: b = b + f"\n## Response ({actor})\n\n{a.note}\n" h['checksum'] = checksum_for(h, b) with open(p, 'w', encoding='utf-8') as f: f.write(render_message(h, b)) ``` ### Technical Analysis The `show` command calculates whether the stored checksum matches the current message, but `cmd_status()` does not perform that verification before changing the message. If a message body or header is modified directly, `cmd_status()` accepts the altered data, updates the status, and computes a new valid checksum over the tampered content. The status operation therefore launders prior tampering into an apparently checksum-valid message. Additionally, an unkeyed SHA-256 checksum only detects accidental corruption when the stored digest is protected separately. Any party that can edit the message can calculate a new digest. It does not provide cryptographic authenticity against ...[truncated 1200 chars]
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
assets/blueprint/scripts/taskctl.py:49
Finding

Task State Machine Does Not Enforce Actor or Reviewer Authorization

Content
View full analysis
{nxt}') if nxt=='CLAIMED' and not a.actor: raise SystemExit('CLAIMED requires --actor owner') if cur=='IN_PROGRESS' and nxt=='REVIEW' and (a.actor and a.actor==d.get('owner')): raise SystemExit('self-review forbidden') d['status']=nxt d['updated_at']=now() if nxt=='CLAIMED': d['owner']=a.actor d['claimed_at']=now() save(p,d) event({'ts':now(),'type':'task_transition','task_id':a.task_id, 'from':cur,'to':nxt,'actor':a.actor}) print(f'{a.task_id}: {cur} -> {nxt}') ``` ```python t=sp.add_parser('transition') t.add_argument('--task-id',required=True) t.add_argument('--to',required=True) t.add_argument('--actor',required=False) t.set_defaults(func=cmd_transition) ``` ### Technical Analysis The actor is optional for all transitions except transitions into `CLAIMED`, and supplied actor values are not authenticated. The state machine checks whether a transition is structurally allowed but does not verify that the caller is authorized to perform it. The purported self-review check is applied to `IN_PROGRESS -> REVIEW`. Moving a task into review is normally an owner action, so preventing the owner from performing that transition does not correctly enforce independent review. More importantly, the code does not restrict `REVIEW -> DONE` to the configured reviewer or require that the approving reviewer differ from the owner. No check ensures that: - Work transitions are performed by the task ow ...[truncated 1375 chars]
Remediation
View remediation
CLAIMED`: authenticated claimant. - `CLAIMED -> IN_PROGRESS`: current owner only. - `IN_PROGRESS -> REVIEW`: current owner only. - `REVIEW -> DONE`: configured reviewer only. - Review rejection or blocking: configured reviewer or explicitly authorized Team Lead. - Enforce `reviewer != owner` when tasks are created, claimed, and approved. - Reject tasks with missing required schema fields. - Record the authenticated principal rather than the caller-provided label. - Add tests for anonymous transitions, owner self-approval, non-reviewer approval, and actor spoofing. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/install_blueprint.sh:6
Finding

Missing Log Directory Causes State Changes Without Corresponding Audit Events

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • 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 (2)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding

The skill instructs users to run shell commands and Python tooling that can read from and write to the filesystem, but it does not declare any explicit tool scope such as permissions or allowed-tools. In a multi-agent control-plane skill, this omission weakens least-privilege guarantees and can let an agent invoke broader file or shell capabilities than reviewers or operators expect.

Content

No source excerpt is available for this finding.

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
75% confidence
Finding

Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Content

Scanner excerpt · references/operations-checklist.md (reported line 21)May include surrounding context.

md
## Security checks

- Coder write scope constrained to coder workspace.
- QA/Ops deploy actions blocked without approval ticket.
- Team Lead-only mailbox GC enforced.

Static analysis

No suspicious patterns detected.