【Bug已解决】macOS detects Codex Computer Use.app as malware and deletes it! 解决方案

发布时间:2026/7/20 18:41:22
【Bug已解决】macOS detects Codex Computer Use.app as malware and deletes it! 解决方案 【Bug已解决】macOS detects Codex Computer Use.app as malware and deletes it! 解决方案原始报错macOS detects Codex Computer Use.app as malware and deletes it! 场景用户下载并打开Codex Computer Use.appmacOS 的 Gatekeeper / XProtect 把它判定为恶意软件直接删除或 quarantine 后阻止运行并提示已移动至废纸篓。应用根本起不来。 关键词macOS 应用包、Gatekeeper、XProtect、代码签名、公证notarization、隔离属性quarantine、应用包结构。一、现象长什么样用户操作从网页/渠道拿到Codex Computer Use.app一个.appbundle双击打开macOS 弹出无法打开因为 Apple 无法检查其是否包含恶意软件或直接由 XProtect 删掉应用消失在废纸篓无法运行用codesign --verify检查发现签名无效或不完整或根本没签名。对最终用户来说这就是我的 Mac 把应用当病毒删了。对开发者来说根因几乎都在签名/公证链条不完整或隔离属性没清掉。二、背景macOS 怎么判定一个 .app 是否安全macOS 对从网络下载的应用有多道防线针对的是.appbundle 整体代码签名Code Signing.app/Contents/MacOS/里的可执行文件、框架、资源都要用开发者证书签名且签名要覆盖整个 bundle含Contents/_CodeSignature/CodeResources清单。公证Notarization开发者把 app 上传 Apple 扫描拿到ticket用xcrun stapler staple把 ticket 钉进 app。用户打开时 Gatekeeper 校验 ticket。隔离属性quarantine从浏览器下载的 app 会被打上com.apple.quarantine扩展属性首次打开必经 Gatekeeper 检查。XProtect系统级恶意软件特征库命中即删。.appbundle 比单个 CLI 二进制复杂它是一个目录树签名必须递归覆盖每一层可执行文件、dylib、嵌套 framework、资源任何一层漏签或哈希不符整个 bundle 的校验就失败。三、根因签名/公证链有缺口根因拆解针对 app bundle整体未签名或部分签名只签了主可执行文件没签嵌套的 dylib / frameworkbundle 校验失败。未公证有签名但没上传 Apple 拿 ticketGatekeeper 在较新 macOS 上直接拦。quarantine 未清用户用curl/浏览器下载后没清com.apple.quarantine打开即触发检查。entitlements 不匹配app 需要的权限如屏幕录制、辅助功能Computer Use 类应用常需在签名时没声明运行时被拒或特征异常引 XProtect 误判。签名在打包后破损签名后又改了 bundle 内文件改 Info.plist、替换资源签名失效。下面用最小模型复现带 quarantine 且签名无效导致校验失败再给修复。四、最小可运行复现校验逻辑模拟用 Python 模拟校验一个 app bundle检查签名清单是否完整、是否带 quarantine。import hashlib, os, json class AppBundleVerifier: def __init__(self, bundle_root): self.root bundle_root def has_quarantine(self) - bool: # 模拟读取 com.apple.quarantine 扩展属性 qp os.path.join(self.root, .quarantine) return os.path.exists(qp) def signature_intact(self, code_resources: dict, actual_files: list) - bool: # code_resources 是签名时记录的哈希清单 for rel in actual_files: recorded code_resources.get(rel) if recorded is None: return False # 清单没覆盖该文件 - 签名不完整 live hashlib.sha256( open(os.path.join(self.root, rel), rb).read()).hexdigest()[:8] if live ! recorded: return False # 哈希不符 - 签名破损 return True if __name__ __main__: # 假设某文件不在签名清单里 verifier AppBundleVerifier(/tmp/Codex.app) code_resources {Contents/MacOS/Codex: abc123} # 漏了嵌套 framework actual [Contents/MacOS/Codex, Contents/Frameworks/Helper.framework/Helper] print(签名完整?, verifier.signature_intact(code_resources, actual)) # False运行输出False——嵌套 framework 没进签名清单bundle 校验失败这正是 Gatekeeper 拒绝/删除的根因之一。五、方案递归签名整个 app bundle第一层签名必须覆盖 bundle 内每一层。用codesign --deep --force --sign递归签所有可执行组件真实命令注释说明不在 Python 内编造import subprocess, shlex def sign_app_bundle(bundle_path: str, identity: str) - int: 递归签名整个 .app bundle。真实调用 codesign。 cmd [ codesign, --deep, --force, --sign, identity, bundle_path, ] print(执行:, shlex.join(cmd)) # 真实环境运行 return subprocess.call(cmd) def verify_app(bundle_path: str) - int: 校验签名。真实调用 codesign --verify --verbose。 cmd [codesign, --verify, --verbose2, bundle_path] print(执行:, shlex.join(cmd)) return subprocess.call(cmd) if __name__ __main__: # 演示调用不会真跑需真实证书与 app print(签名命令示例已生成实际需有效的 Developer ID Application 证书) sign_app_bundle(/Applications/Codex Computer Use.app, Developer ID Application: Acme) verify_app(/Applications/Codex Computer Use.app)--deep保证嵌套的 framework / dylib 都被签消除清单漏项。六、方案公证并 staple ticket第二层签名后上传 Apple 公证拿到 ticket 钉进 app让用户离线也能过 Gatekeeperdef notarize_and_staple(bundle_path: str, keychain_profile: str) - int: # 1) 上传公证 submit [ xcrun, notarytool, submit, bundle_path, --keychain-profile, keychain_profile, --wait, ] rc subprocess.call(submit) if rc ! 0: return rc # 2) 把 ticket 钉进 appstapler staple [xcrun, stapler, staple, bundle_path] return subprocess.call(staple) if __name__ __main__: print(公证流程notarytool submit - stapler staple) notarize_and_staple(/Applications/Codex Computer Use.app, my-profile)stapler 把 ticket 嵌入 app 内部用户首次打开无需联网查 AppleGatekeeper 直接放行。七、方案清除隔离属性 校验 entitlements第三层分发时清掉 quarantine或指导用户用xattr -dr清并确保 entitlements 覆盖应用所需权限Computer Use 类常需屏幕录制等def remove_quarantine(bundle_path: str) - int: 清除 com.apple.quarantine 扩展属性。 cmd [xattr, -dr, com.apple.quarantine, bundle_path] print(执行:, shlex.join(cmd)) return subprocess.call(cmd) def check_entitlements(bundle_path: str, required: list) - list: 检查 app 的 entitlements 是否声明了所需权限。 out subprocess.run( [codesign, -d, --entitlements, :-, bundle_path], capture_outputTrue, textTrue, ) missing [e for e in required if e not in out.stdout] return missing if __name__ __main__: remove_quarantine(/Applications/Codex Computer Use.app) needed [ com.apple.security.cs.allow-jit, com.apple.security.screen-capture, # 屏幕类应用常需 ] missing check_entitlements(/Applications/Codex Computer Use.app, needed) print(缺失的 entitlements:, missing)清 quarantine 让首次打开不再触发 Gatekeeper 拦entitlements 检查确保运行时权限与签名一致避免异常行为招来 XProtect 误判。八、验证本地校验脚本交付前自检def self_check(bundle_path: str) - dict: import os report {} # 1. quarantine 应已清 report[quarantine_cleared] not os.path.exists( os.path.join(bundle_path, .quarantine)) # 2. 签名可校验 report[signature_ok] (verify_app(bundle_path) 0) # 3. entitlements 覆盖所需 report[entitlements_missing] check_entitlements( bundle_path, [com.apple.security.screen-capture]) return report if __name__ __main__: rep self_check(/Applications/Codex Computer Use.app) print(交付前自检:, rep) # 全绿才发布签名 ok quarantine 清 entitlements 齐把self_check放进发布流水线签名/公证/entitlements 任一缺失都不发布从源头杜绝用户下载即被删。九、排查清单.app 被当恶意软件删除按顺序查签名完整性bundle 内每一层可执行、dylib、framework、资源是否都签了codesign -vvv是否通过公证是否上传 Apple 拿到 ticket 并stapler staple新 macOS 无 ticket 会被拦。quarantine从网络下载后com.apple.quarantine是否清除entitlements应用所需权限屏幕录制/辅助功能等是否在签名时声明打包后改动签名后是否又改过 bundle 内文件改动会废掉签名。XProtect 误判是否因行为异常如缺权限导致古怪行为触发特征库补全 entitlements 通常缓解。证书有效用的 Developer ID 证书是否仍在有效期内、未被吊销十、小结macOS 把 .app 当恶意软件删除是签名/公证/隔离属性链条有缺口导致的 Gatekeeper/XProtect 拦截。区别于单文件二进制.app是目录树签名必须递归覆盖每一层。修复三层递归签名codesign --deep覆盖可执行、dylib、framework、资源清单不漏项公证 staple上传 Apple 拿 ticket 并钉进 app离线可过 Gatekeeper清 quarantine 齐 entitlements分发时清隔离属性签名时声明应用所需权限。核心原则.app的安全校验看的是整个 bundle 的完整性不是主可执行文件一个。递归签名、公证、正确的 entitlements三者齐备用户下载打开才不会被系统当成恶意软件删掉。