T09 · Insecure Skill Coding Practices
- Location
scripts/morning_brief.py:738- Finding
Morning dry-run mode still transmits sensitive portfolio data to a configurable webhook
- Content
View full analysis
None: """Send notification via Slack webhook. Silent on failure.""" webhook_url = os.environ.get("OPENCLAW_SLACK_WEBHOOK", "") if not webhook_url: try: config = load_config() webhook_url = config.get("slack_webhook_url", "") except Exception: pass if not webhook_url: return try: data = json.dumps({"text": message}).encode("utf-8") req = urllib.request.Request(webhook_url, data=data, headers={"Content-Type": "application/json"}) urllib.request.urlopen(req, timeout=10) except Exception: pass ``` ```python parser.add_argument("--dry-run", action="store_true", help="Don't send, just print") parser.add_argument("--debug", action="store_true", help="Enable debug logging") parser.add_argument("--test-slack", action="store_true", help="Send a test Slack notification and exit") ``` ```python brief = build_morning_brief(config, kalshi, debug=args.debug) print(brief) # Send to Slack if configured _notify_slack(brief) ``` ### Technical Analysis The command-line interface explicitly states that `--dry-run` will not send the generated briefing. However, `args.dry_run` is never evaluated before `_notify_slack(brief)` is called. Consequently, all executions—including dry runs—send the complete briefing whenever `OPENCLAW_SLACK_WEBHOOK` is present. The transmitted message can contain sensitive financial information, including: - Kalshi positions and market exposure - Position quantities - Cost basis - Unrealized profit and loss - Trading signals and inferred strategy - Cross-platform market opportunities The webhook URL is taken directly from an environment variable and passed to `urllib.req ...[truncated 1785 chars]- Remediation
View remediation
