T09 · Insecure Skill Coding Practices
- Location
scripts/report_openclaw_token_usage.py:328- Finding
Spreadsheet Formula Injection in CSV Exports
- Content
View full analysis
list[Path]: out_dir.mkdir(parents=True, exist_ok=True) written: list[Path] = [] def write_csv(path: Path, header: list[str], rows: list[list[object]]) -> None: with path.open('w', encoding='utf-8', newline='') as f: writer = csv.writer(f) writer.writerow(header) writer.writerows(rows) written.append(path) summary = data['summary'] write_csv( out_dir / 'summary.csv', ['timezone', 'start', 'end', 'input', 'output', 'cacheRead', 'cacheWrite', 'totalTokens', 'messages'], [[ data['assumption_timezone'], data['range_local']['start'], data['range_local']['end'], summary['input'], summary['output'], summary['cacheRead'], summary['cacheWrite'], summary['totalTokens'], summary['messages'] ]], ) rows = [] for day, agents in data['by_day_agent'].items(): for agent, m in agents.items(): rows.append([day, agent, m['input'], m['output'], m['cacheRead'], m['cacheWrite'], m['totalTokens'], m['messages']]) write_csv(out_dir / 'by_day_agent.csv', ['day', 'agent', 'input', 'output', 'cacheRead', 'cacheWrite', 'totalTokens', 'messages'], rows) rows = [] for agent, m in data['by_agent'].items(): rows.append([agent, m['input'], m['output'], m['cacheRead'], m['cacheWrite'], m['totalTokens'], m['messages']]) write_csv(out_dir / 'by_agent.csv', ['agent', 'input', 'output', 'cacheRead', 'cacheWrite', 'totalTokens', 'messages'], rows) rows = [] for model, m in data['by_model'].items(): rows.append([model, m['input'], m['output'], m['cacheRead'], m['cacheWrite'], m['totalTokens'], m['messages']]) write ...[truncated 3827 chars]- Remediation
View remediation
object: if not isinstance(value, str): return value probe = value.lstrip(' \t\r\n') if probe.startswith(FORMULA_PREFIXES): return "'" + value return value def write_csv(path: Path, header: list[str], rows: list[list[object]]) -> None: safe_header = [spreadsheet_safe(value) for value in header] safe_rows = [ [spreadsheet_safe(value) for value in row] for row in rows ] with path.open('w', encoding='utf-8', newline='') as f: writer = csv.writer(f) writer.writerow(safe_header) writer.writerows(safe_rows) ``` Add regression tests for: - Each dangerous prefix: `=`, `+`, `-`, and `@` - Dangerous prefixes preceded by spaces, tabs, or carriage returns - Formula-like agent names, providers, models, session keys, and filenames - Ordinary text and numeric metrics to ensure they remain unchanged - CSV files opened in the spreadsheet applications supported by the project Documentation should also warn users that previously generated CSV files may contain ...[truncated 120 chars]
