Back to skill

Security audit

miab-broker

Security checks for vulnerabilities and agentic risk

Overview

This broker is not malicious, but it should be reviewed because it persists callback content and lets local agents change wake routing without real authentication.

Install only for a trusted single-user agent ensemble. Do not put secrets in task, summary, result, or resume fields; keep $CLAW_HOME private; review who can run the CLI; be careful with register, --session-key, --force, --allow-outside, and any scheduled reaper settings.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • 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
  • 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/bin/claw-callback.py:212
Finding

Unauthenticated Callback Mutation and Wake-Route Replacement

Content
View full analysis
bool: """Enforce that `actor` is the agent entitled to take `action` on this bottle. (T15) Returns True when the check was overridden with --force, so the caller can record an `authority-override` ledger event. Refuses (fail-closed, non-zero) otherwise. Comparison is on canonical names (T14): an agent that returns as `ECHO` when the envelope recorded `reviewer` is the same agent, and rejecting it would be a regression rather than a control. """ if agent_key(actor) == agent_key(expected): return False if force: return True die(f"{action} refused: --from '{actor}' is not the {role} of {env['id']} " f"(that is '{expected}'). If this is deliberate, re-run with --force; the " f"override is recorded in the ledger.") ``` The `--force` option bypasses the comparison without requiring a distinct administrative credential. More importantly, a caller can simply provide the expected agent name through `--from`, because no credential or cryptographic proof is bound to that identity. The routing registry is also writable without an administrator check. Registering an existing logical agent updates its `agentId` and optional `sessionKey`: ```python def cmd_register(args): """Register or update an agent's routing info in the registry. (T14)""" reg = load_registry() age ...[truncated 3221 chars]
Remediation
View remediation

T01 · Skill Instruction Hijacking

Warning
Location
scripts/bin/claw-callback.py:380
Finding

Untrusted Resume Content Is Rendered as Agent Instructions

Content
View full analysis
dict: """Schema-validate a resume object arriving from --resume-json/--resume-file — both are untrusted input that lands verbatim in the dispatch_message sent to another agent. (T7 / S3)""" if not isinstance(resume, dict): die("resume context must be a JSON object") extra = set(resume.keys()) - RESUME_ALLOWED_KEYS if extra: die(f"resume context has unknown keys: {sorted(extra)}") if "summary" in resume and not isinstance(resume["summary"], str): die("resume.summary must be a string") if "steps" in resume and not (isinstance(resume["steps"], list) and all(isinstance(s, str) for s in resume["steps"])): die("resume.steps must be a list of strings") if "expects" in resume and not isinstance(resume["expects"], str): die("resume.expects must be a string") if "integrate" in resume and not isinstance(resume["integrate"], str): die("resume.integrate must be a string") return resume ``` The validated strings are then inserted directly into the wake message under instruction-oriented headings: ```python def wake_message(cid: str, target: str, resume: dict, results: list, terminal: bool) -> str: """The exact text the finishing agent should send to `target` via agent-to-agent.""" last = results[-1] if results else None lines = [ f"RESUME callback ...[truncated 2900 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/bin/claw-callback.py:299
Finding

Race Conditions and Predictable Shared Temporary Files in Callback State Updates

Content
View full analysis
Path: """Atomic write.""" env["updatedAt"] = now_iso() p = envelope_path(env["id"]) tmp = p.with_suffix(".json.tmp") tmp.write_text(json.dumps(env, indent=2, ensure_ascii=False)) os.chmod(tmp, 0o600) # T5 / S2 tmp.replace(p) return p ``` The final `replace()` operation is atomic, but the overall transaction is not. Mutation commands independently: 1. Load an envelope. 2. Modify an in-memory copy. 3. Write to the same `.json.tmp` path. 4. Replace the final envelope. There is no per-callback lock, revision number, compare-and-swap validation, or unique temporary filename. Two processes can therefore load the same prior revision and overwrite each other's updates. They can also concurrently truncate or replace the shared temporary file. The registry save path uses the same pattern: ```python def save_registry(reg: dict) -> None: reg["updatedAt"] = now_iso() p = registry_path() tmp = p.with_suffix(".json.tmp") tmp.write_text(json.dumps(reg, indent=2, ensure_ascii=False)) os.chmod(tmp, 0o600) # T5 / S2 tmp.replace(p) ``` Restrictive permissions reduce cross-user interference but do not protect against concurrent broker processes running under the same account. ### Attack Path 1. Two processes invoke mutating commands against the same callback at nearly the same time, such as two `return` operations or a `return` concurrent with `cancel`. 2. Both processes load the same envelope revision and independently pass the holder or originator checks. 3. Both modify their in-memory cop ...[truncated 1165 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Rogue AgentSelf-Modification, Session Persistence
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (19)

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 83)May include surrounding context.

md
## 2. Callback Lifecycle (the `claw-callback.py` CLI)

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 87)May include surrounding context.

md
## 2. Callback Lifecycle (the `claw-callback.py` CLI)

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 233)May include surrounding context.

md
| `$CLAW_HOME/logs/callback-reaper.log` | `reap-callbacks.sh` | reaper run log |

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 306)May include surrounding context.

md
| `$CLAW_HOME/logs/callback-reaper.log` | `reap-callbacks.sh` | reaper run log |

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 311)May include surrounding context.

md
| `$CLAW_HOME/logs/callback-reaper.log` | `reap-callbacks.sh` | reaper run log |

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 312)May include surrounding context.

md
| `$CLAW_HOME/logs/callback-reaper.log` | `reap-callbacks.sh` | reaper run log |

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 313)May include surrounding context.

md
| `$CLAW_HOME/logs/callback-reaper.log` | `reap-callbacks.sh` | reaper run log |

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · CHANGELOG.md (reported line 193)May include surrounding context.

md
overridden and the unchanged path.

- **Declared permissions in `SKILL.md` frontmatter** (T8). A `permissions:` block now states the
  environment variables read (`CLAW_HOME`, `CALLBACK_TTL_MIN`), the exact file read/write globs,
  and that the skill makes no network calls — addressing SkillSpector **LP3** (confidence 0.94),
  which flagged that a skill enabling persistent state manipulation and wake-routing changes
  declared only `name` and `description`. The declaration matches what the code already enforces

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · CHANGELOG.md (reported line 327)May include surrounding context.

md
`agent-registry.json` and control where `wake` events are delivered.
- **[T5 / S2 — MEDIUM]** `os.umask(0o077)` set at process entry;
  `state/callbacks/` and `archive/` (and its subdirectories) are explicitly
  `chmod 0700`; envelope, registry, and ledger files are `chmod 0600` before
  being made visible via atomic replace. State created under a permissive
  ambient umask is no longer world-readable.
- **[T7 / S3 — MEDIUM]** `--resume-file` is confined to `$CLAW_HOME` unless

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · CHANGELOG.md (reported line 327)May include surrounding context.

md
`agent-registry.json` and control where `wake` events are delivered.
- **[T5 / S2 — MEDIUM]** `os.umask(0o077)` set at process entry;
  `state/callbacks/` and `archive/` (and its subdirectories) are explicitly
  `chmod 0700`; envelope, registry, and ledger files are `chmod 0600` before
  being made visible via atomic replace. State created under a permissive
  ambient umask is no longer world-readable.
- **[T7 / S3 — MEDIUM]** `--resume-file` is confined to `$CLAW_HOME` unless

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · SECURITY.md (reported line 80)May include surrounding context.

md
- **Do not put secret values in `--task`, `--summary`, `--result`, or resume fields.** They are
  written to disk in plaintext and are copied into the `dispatch_message` text sent to other
  agents. Reference a secret's *location*, never its value — and prefer not to reference it at all.
- **Keep `$CLAW_HOME` private** (`chmod 700`). The broker enforces this on its root, but the
  surrounding directory tree is your responsibility.
- **Only run the broker among agents you trust.** Given no actor authentication, any participant
  can disrupt any chain.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · SKILL.md (reported line 330)May include surrounding context.

md
- **Do not put secret values in `--task`, `--summary`, `--result`, or resume fields.** They are
  written to disk in plaintext and are copied into the `dispatch_message` text sent to other
  agents. Reference a secret's *location*, never its value — and prefer not to reference it at all.
- **Keep `$CLAW_HOME` private** (`chmod 700`). The broker enforces this on its root, but the
  surrounding directory tree is your responsibility.
- **Only run the broker among agents you trust.** Given no actor authentication, any participant
  can disrupt any chain.

Session Persistence

Medium
Category
Rogue Agent
Confidence
92% confidence
Finding

The skill explicitly persists callback envelopes, results, and ledger entries to disk and instructs agents to include task summaries, steps, expectations, and results in those records. Because these messages can contain operational context or secrets, this creates session/task persistence that may expose sensitive data to other local processes, backups, logs, or later forensic review if operators misuse the channel.

Content

Scanner excerpt · SKILL.md (reported line 124)May include surrounding context.

The caller creates a bottle, packages its resume context, dispatches, and ends its turn.

bash
python3 <miab-broker>/scripts/bin/claw-callback.py create \
  --task "Analyze the generated architecture files" \
  --from main --to planner \
  --summary "Awaiting SPECTRE's architecture spec to integrate into the build plan" \

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · scripts/bin/claw-callback.py (reported line 19)May include surrounding context.

python
wakes that agent. See CALLBACKS.md for the full protocol.

Subcommands:
  create   originator delegates work, registers a callback         (push origin frame)
  forward  a holder delegates further, packaging prior callbacks   (push another frame)
  return   the current holder finishes, wakes the next agent       (pop top frame)
  resolve  the origin completes the whole task; clean up           (delete + ledger)

Unsafe Defaults

Medium
Category
Tool Misuse
Confidence
70% confidence
Finding

Tool defaults are unsafe or overly permissive (e.g. disabled TLS verification, no authentication, world-writable permissions). Unsafe defaults widen the attack surface.

Content

Scanner excerpt · CHANGELOG.md (reported line 256)May include surrounding context.

md
The mode check is a bitmask test, not a numeric one: any group-or-other bit
    (0o077) being set is refused, regardless of what the owner triad is. A plain
    `mode > 0o700` comparison is wrong here — e.g. 0o550 and 0o505 are both
    numerically <= 0o700 but are group- or world-readable.
    """
    if not root.exists():
        return

Unsafe Defaults

Medium
Category
Tool Misuse
Confidence
70% confidence
Finding

Tool defaults are unsafe or overly permissive (e.g. disabled TLS verification, no authentication, world-writable permissions). Unsafe defaults widen the attack surface.

Content

Scanner excerpt · CHANGELOG.md (reported line 329)May include surrounding context.

md
The mode check is a bitmask test, not a numeric one: any group-or-other bit
    (0o077) being set is refused, regardless of what the owner triad is. A plain
    `mode > 0o700` comparison is wrong here — e.g. 0o550 and 0o505 are both
    numerically <= 0o700 but are group- or world-readable.
    """
    if not root.exists():
        return

Unsafe Defaults

Medium
Category
Tool Misuse
Confidence
70% confidence
Finding

Tool defaults are unsafe or overly permissive (e.g. disabled TLS verification, no authentication, world-writable permissions). Unsafe defaults widen the attack surface.

Content

Scanner excerpt · scripts/bin/claw-callback.py (reported line 89)May include surrounding context.

python
The mode check is a bitmask test, not a numeric one: any group-or-other bit
    (0o077) being set is refused, regardless of what the owner triad is. A plain
    `mode > 0o700` comparison is wrong here — e.g. 0o550 and 0o505 are both
    numerically <= 0o700 but are group- or world-readable.
    """
    if not root.exists():
        return

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The --allow-outside flag permits reading arbitrary JSON files outside CLAW_HOME and using their contents as resume context. In this callback system, resume data is later embedded into wake/dispatch messages for other agents, so a user or upstream agent can exfiltrate sensitive local file contents by pointing to an arbitrary readable file and forwarding it through the agent workflow.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

Contents loaded from an external resume file are accepted and stored as trusted resume context, then later inserted into dispatch_message and sent to another agent. That creates a data-flow path from arbitrary local file read to inter-agent transmission, which can leak secrets or sensitive internal state without any explicit disclosure at the forwarding point.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.