DEFAULT_CONFIG ship agent_security.sandbox_pw = "" kể từ commit3827552, và cấu hình đưa tới dialog luôn được deep-merge với defaults đó. Nghĩa là trên mọi bản cài không đặt COWORK_SANDBOX_PASSWORD, mật khẩu đã lưu là chuỗi rỗng — và phép so `pw == self._sandbox_pw` nhận luôn ô nhập trống. Bấm Unlock với ô trống là mở được toàn bộ nhóm Sandbox Security. Commit3827552chỉ sửa config.py nên bỏ sót bản sao thứ hai của literal nằm trong ui/settings_dialog.py, và chính nó tạo ra lỗ hổng rỗng này. Sửa: - gỡ literal credential khỏi mã nguồn (nó vốn là code chết: deep-merge làm tham số mặc định của .get() không bao giờ chạy); - chặn rỗng trước khi so, theo đúng mẫu mà MS365 unlock đã dùng; - so sánh timing-safe trên BYTES, không trên str — secrets.compare_digest ném TypeError với str ngoài ASCII, mà app mặc định tiếng Việt và phục vụ khách Nhật nên mật khẩu có dấu là input bình thường; - chưa đặt mật khẩu thì báo đúng trạng thái đó, không báo "sai mật khẩu" — người dùng sẽ gõ lại mãi một thứ không tồn tại. Root cause: ui/settings_dialog.py:104 (bản cũ) Test: tests/ui/test_sandbox_unlock_security.py LƯU Ý CHO REVIEWER: literal cũ vẫn nằm trong 6 commit của Git history. Gỡ ở đây không gỡ khỏi lịch sử — cần xoay credential trên các máy còn giá trị đó trong config.json. Không rewrite history (SECURITY.md). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>