T05 · Unauthorized Access and Privilege Escalation
- Location
scripts/budget_audit.py:46- Finding
Symlink Following Allows Unauthorized File Modification
- Content
View full analysis
dict: """Audit one agent's budget. Returns report dict.""" budget_path = os.path.join(agent_dir, "BUDGET.json") if not os.path.exists(budget_path): return {"agent": agent_name, "status": "no_budget_file"} with open(budget_path) as f: budget = json.load(f) ``` The same path is subsequently opened for writing in both the daily-reset and same-day execution paths: ```python with open(budget_path, "w") as f: json.dump(budget, f, indent=2) ``` ```python with open(budget_path, "w") as f: json.dump(budget, f, indent=2) ``` Agent directories are discovered without validating the contained budget file: ```python agent_dirs = sorted(glob.glob(os.path.join(AGENTS_DIR, "*"))) for agent_dir in agent_dirs: if not os.path.isdir(agent_dir): continue dirname = os.path.basename(agent_dir) if dirname == "governance": continue agent_name = AGENT_MAP.get(dirname, dirname) budget_path = os.path.join(agent_dir, "BUDGET.json") if not os.path.exists(budget_path): continue report = audit_agent(agent_dir, agent_name, today) reports.append(report) ``` ### Technical Analysis The auditor opens `BUDGET.json` through a pathname without rejecting symbolic links or verifying that the resolved file remains inside the expected agent directory. Python's ordinary `open()` follows symbolic links. The script then rewrites the same resolved target after changing budget-related fields. This creates a privilege-boundary problem when an agent can modify its own directory while the audit runs under a more privileged orchestrator or heartbeat account. ...[truncated 1800 chars]- Remediation
View remediation
