T05 · Unauthorized Access and Privilege Escalation
Error
- Location
- jj-mailbox.sh:139
- Finding
- Path Traversal Allows File Access Outside the Mailbox Repository<![CDATA[ ## Vulnerability Details **File Location**: `jj-mailbox.sh:139-155`, `jj-mailbox.sh:167-218`, and `jj-mailbox.sh:232-280` **Vulnerability Type**: Path traversal and insufficient path authorization **Risk Level**: High The script uses agent-controlled identifiers directly as filesystem path components. It does not reject absolute paths, `/`, `..`, or symlinked directories, contradicting the scope guarantee in `SKILL.md:18` that the Skill only accesses files inside `$JJ_MAILBOX_REPO`. ### Vulnerable Code Registration creates directories and files using an unvalidated agent name: ```bash cmd_register() { ensure_repo ensure_jj local name="${1:?Usage: jj-mailbox register <name>}" local desc="${2:-Agent ${name}}" local repo repo="$(get_repo)" cd "${repo}" # Create agent directories mkdir -p "agents/${name}" "inbox/${name}/new" "inbox/${name}/processed" # Write profile cat > "agents/${name}/profile.json" <<EOF { "name": "${name}", "description": "${desc}", "capabilities": [], "platform": "openclaw", "created": "$(ts_iso)" } EOF ``` Message sending uses an unvalidated recipient and sender in directory and filename construction: ```bash cmd_send() { ensure_repo ensure_jj local to="${1:?Usage: jj-mailbox send <to> <subject> <body> [--refs <id1,id2,...>]}" local subject="${2:?}" local body="${3:?}" local refs_arg="" local from from="$(get_agent)" local repo repo="$(get_repo)" # Parse optional --refs flag (remaining args after positional 3) shift 3 || true while [[ $# -gt 0 ]]; do case "$1" in --refs) refs_arg="${2:-}"; shift 2 ;; *) shift ;; esac done cd "${repo}" # Verify recipient exists if [[ ! -d "inbox/${to}/new" ]]; then err "Unknown agent: ${to}" err "Registered agents:" ls agents/ 2>/dev/null || echo " (none)" exit 1 fi local msg_id="msg-$(gen_id)" local ts ts="$(ts_filename)" local filename="${ts}_${from}_${msg_id}.json" # Buil ...[truncated 4744 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. **Strictly validate every agent identifier** Apply the same validation to registration names, recipients, explicit inbox/read selectors, and `JJ_MAILBOX_AGENT`. Use a conservative allowlist, for example: ```bash validate_agent_name() { local name="$1" if [[ ! "$name" =~ ^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$ ]] || [[ "$name" == "." || "$name" == ".." ]]; then err "Invalid agent name" exit 1 fi } ``` This rejects separators, traversal components, whitespace, control characters, and absolute paths. 2. **Canonicalize and enforce repository containment** Resolve the repository and every target path to canonical absolute paths before access. Verify that the result begins with the canonical repository path followed by `/`; a textual prefix check without the separator is insufficient. Prefer descriptor-based or component-by-component traversal protections where available, because simple canonicalization can remain vulnerable to time-of-check/time-of-use races. 3. **Reject symlinked mailbox directories** Before reading or writing, verify that relevant components such as `agents`, `inbox`, the selected agent directory, `new`, and `processed` are real directories and not symbolic links. Do not follow attacker-controlled symlinks outside the repository. 4. **Use safe file creation** Create new messages with exclusive semantics so existing files cannot be overwritten. Ensure the destination directory has already passed containment and symlink checks. 5. **Apply authorization rules** The inbox command should normally only read the current agent's inbox unless an explicit administrative mode is enabled. Avoid accepting arbitrary agent selectors when that capability is not required. 6. **Add regression tests** Test and reject identifiers including: ```text . .. ../target ../../target /tmp/target agent/name agent\name ``` Tests s ...[truncated 165 chars]
