Back to skill

Security audit

MacCheck

Security checks for vulnerabilities and agentic risk

Overview

This is a coherent local Mac inspection skill, but it saves detailed device reports on disk that users should protect.

Install only if you are comfortable with a local Mac health check saving detailed system inventory, serial number, and report files under the chosen output directory. Keep those files private, delete them when no longer needed, and avoid sharing exported reports without reviewing the serial number and device details.

Vulnerability Patterns
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (1)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/prepare-session.jxa:10
Finding

Local Session Artifacts Are Created Without Restrictive Permissions

Content
View full analysis

Vulnerability Details

File Location: scripts/prepare-session.jxa:10-20
Related Locations: scripts/collect-system.sh:6-7, scripts/helpers/safe-command.sh:12-15, 22-24, scripts/build-session.jxa:51-56
Vulnerability Type: Insecure permissions on locally retained sensitive data
Risk Level: Medium

Vulnerable Code

scripts/prepare-session.jxa:10-20:

javascript
var fm = $.NSFileManager.defaultManager;
var root = $(argv[0]).stringByStandardizingPath.js;
var locale = argv[1] || 'zh-CN';
if (locale !== 'zh-CN' && locale !== 'en-US') fail('unsupported locale: ' + locale);
fm.createDirectoryAtPathWithIntermediateDirectoriesAttributesError(root, true, $(), null);
var now = new Date();
function pad(n) { return String(n).padStart(2, '0'); }
var stamp = now.getFullYear() + pad(now.getMonth() + 1) + pad(now.getDate()) + '-' + pad(now.getHours()) + pad(now.getMinutes()) + pad(now.getSeconds());
var suffix = Math.random().toString(16).slice(2, 6).toUpperCase().padEnd(4, '0');
var id = stamp + '-' + suffix;
var dir = root + '/' + id;
fm.createDirectoryAtPathWithIntermediateDirectoriesAttributesError(dir + '/raw', true, $(), null);

scripts/helpers/safe-command.sh:12-15, 22-24:

sh
/bin/mkdir -p "$output_dir"
stdout_file="$output_dir/${probe_id}.out"
stderr_file="$output_dir/${probe_id}.err"
meta_file="$output_dir/${probe_id}.meta.json"
sh
"$@" > "$stdout_file" 2> "$stderr_file" &

scripts/build-session.jxa:51-56:

javascript
write(dir+'/session.json',JSON.stringify(session,null,2)+'\n');
var strings=json(root+'/assets/i18n/'+session.locale+'.json'),layoutName=caps.keyboardLayout&&layouts[caps.keyboardLayout]?caps.keyboardLayout:'ANSI';
var payload={session:session,facts:{device:facts.device,battery:facts.battery,security:facts.security,storage:facts.storage,network:facts.network,peripherals:facts.peripherals},system:results,capabilities:caps,checks
...[truncated 3139 chars]
Remediation
View remediation

Remediation Suggestions

  1. Set a restrictive umask before any output is created:

    sh
    umask 077
    

    Place this near the beginning of scripts/run-full-check.sh and defense-in-depth wrappers that can be invoked independently.

  2. Explicitly create the output root, session directory, and raw-data directory with owner-only access equivalent to 0700.

  3. Create all raw output, metadata, JSON, HTML, and report files with owner-only permissions equivalent to 0600. Do not rely exclusively on the caller's environment.

  4. Verify after creation that the output path is owned by the current user, is not a symbolic link, and is not unexpectedly group- or world-writable.

  5. Reject unsafe shared output roots unless the user explicitly acknowledges the risk. Where practical, use a private per-user application-support directory by default.

  6. Document which artifacts contain the full serial number, how long they remain on disk, and how users can securely remove them.

  7. Provide an explicit cleanup command or option that safely removes only the generated session directory after the user has exported any desired report.

  8. Consider masking the serial number by default in HTML and exported reports, with an explicit opt-in for including the complete value.

Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (42)

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding

声明描述的是一个功能完整的 Mac 本地检测工具,涵盖大量系统与硬件信息采集及报告导出。但实际提供的代码片段只是一个包装脚本,用于调用同目录下的 normalize.jxa。由于核心行为隐藏在未提供的 JXA 文件中,该片段既不能支持已声明的主要用途,也不能证明其资源访问方式符合“只读、数据本地、不联网”的关键承诺。基于当前可见代码,描述与行为存在实质性不一致。

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

声明描述的是一个功能完整的 Mac 本地检测/验机工具,但当前代码片段只实现了一个非常有限的辅助动作:打开指定的会话 HTML 文件。代码没有显示任何检测、信息读取、报告导出或页面交互测试逻辑。因此,就该代码片段所实际体现的行为而言,其与声明的主要用途存在明显不匹配。

Content

No source excerpt is available for this finding.

Scope Creep

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The script persists collected device telemetry to facts.json via writeJSON(dir + '/facts.json', facts), which contradicts the stated read-only behavior. Even without network exfiltration, writing a normalized report creates a durable local artifact containing sensitive device, security, storage, and network state that can be accessed later by other processes or users.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The example trigger "Check this Mac for me" is a natural, generic phrase that could plausibly appear in ordinary conversation with an agent. The README does not provide tighter activation constraints, alternate exact trigger phrases, or negative examples to clarify when this skill should or should not be invoked.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The documented trigger phrase "帮我检查这台 Mac。" is broad and closely resembles ordinary user conversation, so an agent could invoke the skill unintentionally during normal chat. Because this skill performs automated local system inspection and opens a local hardware-check page, accidental invocation could expose sensitive device information or trigger actions the user did not explicitly intend.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
81% confidence
Finding

The trigger phrases are broad enough to match common support requests like '检测' or '故障排查', which could cause the agent to launch a full local inspection when the user only wanted advice. In this context, the skill can collect extensive device, battery, storage, network, and security information, so overbroad activation increases privacy exposure and the chance of unintended execution.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

This JSON repeatedly sets "keyboardLayout": "ANSI" for many device profiles and also in generic notebook/desktop fallbacks, which enforces a specific keyboard/locale assumption in natural-language/config data. Under the policy, forcing a specific language/locale setting without user choice or clear region-specific justification is a violation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

This JSON file is entirely a zh-CN localization bundle, exposing all user-facing strings only in Simplified Chinese. Under the policy for natural-language violations, forcing a specific language without visible user opt-in can be a locale-policy issue unless the regional constraint is clearly documented and justified in the file.

Content

No source excerpt is available for this finding.

Scope Creep

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The code persists inspection state to localStorage via localStorage.setItem(...), which contradicts the skill's 'read-only' claim. While this is not remote code execution or exfiltration, it is a real integrity/privacy issue because device inspection results and session identifiers remain stored on the machine beyond the current session.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

The code switches output language based on a hardcoded zh-CN locale check and embeds substantial Chinese-language content, but this file does not show any user choice or documented justification for limiting locale behavior. This can violate language/locale policy when a specific language experience is imposed without explicit opt-in.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The microphone test invokes navigator.mediaDevices.getUserMedia({audio:true}) and records audio with MediaRecorder, but there is no prominent privacy warning immediately before capture explaining that voice/audio will be recorded locally. Browser permission prompts help, but they do not replace an application-level disclosure about what is captured, for how long, and whether it is saved or exportable.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The camera test starts video capture with getUserMedia({video:true}) when the user clicks preview, but the UI does not present a clear in-app warning that live video from the camera will be accessed. In a hardware-checking skill this is contextually expected, yet camera access still involves privacy-sensitive data and should be explicitly disclosed before activation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The entire skill file is written in Chinese and provides no indication that users may opt into another language or locale. Under the policy, forcing a specific language without user choice is a natural-language policy violation unless the restriction is explicitly justified.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The entire architecture document is written in Chinese and provides no indication that language selection is optional or that the skill is intentionally limited to a Chinese-speaking audience. Under the stated policy, forcing a specific language without user opt-in is a natural-language locale violation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

This file’s user-facing natural language is entirely Chinese, including the title, table headings, and explanatory text. Under the policy, forcing a specific language without user opt-in or documented justification is a natural-language policy violation.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · references/detection-catalog.md (reported line 8)May include surrounding context.

md
| 设备 | `system_profiler SPHardwareDataType`、`ioreg IOPlatformExpertDevice`、`sw_vers` | 型号、芯片、内存、系统、序列号一致性 |
| 电池 | `system_profiler SPPowerDataType`、`ioreg AppleSmartBattery` | 支持状态、循环、容量、Condition、充电 |
| 安全与锁定 | `SPHardwareDataType`、`profiles status`、`fdesetup status`、`csrutil status` | 当前 Activation Lock、MDM/ADE、FileVault、SIP;不证明服务器侧未来状态 |
| 存储 | `diskutil info -plist /`、`SPStorageDataType`、`SPNVMeDataType` | 容量、可用空间、文件系统、SMART/NVMe 可见健康 |
| 网络与蓝牙 | `SPAirPortDataType`、`SPBluetoothDataType` | 控制器存在、启用和连接状态;不保存 SSID/设备名 |
| 接口与外设 | USB、Thunderbolt、Display、Audio profiler | 当前枚举摘要;没有外设不代表所有物理接口通过 |

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · scripts/collect-system.sh (reported line 28)May include surrounding context.

sh
| 设备 | `system_profiler SPHardwareDataType`、`ioreg IOPlatformExpertDevice`、`sw_vers` | 型号、芯片、内存、系统、序列号一致性 |
| 电池 | `system_profiler SPPowerDataType`、`ioreg AppleSmartBattery` | 支持状态、循环、容量、Condition、充电 |
| 安全与锁定 | `SPHardwareDataType`、`profiles status`、`fdesetup status`、`csrutil status` | 当前 Activation Lock、MDM/ADE、FileVault、SIP;不证明服务器侧未来状态 |
| 存储 | `diskutil info -plist /`、`SPStorageDataType`、`SPNVMeDataType` | 容量、可用空间、文件系统、SMART/NVMe 可见健康 |
| 网络与蓝牙 | `SPAirPortDataType`、`SPBluetoothDataType` | 控制器存在、启用和连接状态;不保存 SSID/设备名 |
| 接口与外设 | USB、Thunderbolt、Display、Audio profiler | 当前枚举摘要;没有外设不代表所有物理接口通过 |

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · scripts/normalize.jxa (reported line 76)May include surrounding context.

text
| 设备 | `system_profiler SPHardwareDataType`、`ioreg IOPlatformExpertDevice`、`sw_vers` | 型号、芯片、内存、系统、序列号一致性 |
| 电池 | `system_profiler SPPowerDataType`、`ioreg AppleSmartBattery` | 支持状态、循环、容量、Condition、充电 |
| 安全与锁定 | `SPHardwareDataType`、`profiles status`、`fdesetup status`、`csrutil status` | 当前 Activation Lock、MDM/ADE、FileVault、SIP;不证明服务器侧未来状态 |
| 存储 | `diskutil info -plist /`、`SPStorageDataType`、`SPNVMeDataType` | 容量、可用空间、文件系统、SMART/NVMe 可见健康 |
| 网络与蓝牙 | `SPAirPortDataType`、`SPBluetoothDataType` | 控制器存在、启用和连接状态;不保存 SSID/设备名 |
| 接口与外设 | USB、Thunderbolt、Display、Audio profiler | 当前枚举摘要;没有外设不代表所有物理接口通过 |

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · scripts/normalize.jxa (reported line 173)May include surrounding context.

text
| 设备 | `system_profiler SPHardwareDataType`、`ioreg IOPlatformExpertDevice`、`sw_vers` | 型号、芯片、内存、系统、序列号一致性 |
| 电池 | `system_profiler SPPowerDataType`、`ioreg AppleSmartBattery` | 支持状态、循环、容量、Condition、充电 |
| 安全与锁定 | `SPHardwareDataType`、`profiles status`、`fdesetup status`、`csrutil status` | 当前 Activation Lock、MDM/ADE、FileVault、SIP;不证明服务器侧未来状态 |
| 存储 | `diskutil info -plist /`、`SPStorageDataType`、`SPNVMeDataType` | 容量、可用空间、文件系统、SMART/NVMe 可见健康 |
| 网络与蓝牙 | `SPAirPortDataType`、`SPBluetoothDataType` | 控制器存在、启用和连接状态;不保存 SSID/设备名 |
| 接口与外设 | USB、Thunderbolt、Display、Audio profiler | 当前枚举摘要;没有外设不代表所有物理接口通过 |

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · scripts/normalize.jxa (reported line 174)May include surrounding context.

text
| 设备 | `system_profiler SPHardwareDataType`、`ioreg IOPlatformExpertDevice`、`sw_vers` | 型号、芯片、内存、系统、序列号一致性 |
| 电池 | `system_profiler SPPowerDataType`、`ioreg AppleSmartBattery` | 支持状态、循环、容量、Condition、充电 |
| 安全与锁定 | `SPHardwareDataType`、`profiles status`、`fdesetup status`、`csrutil status` | 当前 Activation Lock、MDM/ADE、FileVault、SIP;不证明服务器侧未来状态 |
| 存储 | `diskutil info -plist /`、`SPStorageDataType`、`SPNVMeDataType` | 容量、可用空间、文件系统、SMART/NVMe 可见健康 |
| 网络与蓝牙 | `SPAirPortDataType`、`SPBluetoothDataType` | 控制器存在、启用和连接状态;不保存 SSID/设备名 |
| 接口与外设 | USB、Thunderbolt、Display、Audio profiler | 当前枚举摘要;没有外设不代表所有物理接口通过 |

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · scripts/normalize.jxa (reported line 175)May include surrounding context.

text
| 设备 | `system_profiler SPHardwareDataType`、`ioreg IOPlatformExpertDevice`、`sw_vers` | 型号、芯片、内存、系统、序列号一致性 |
| 电池 | `system_profiler SPPowerDataType`、`ioreg AppleSmartBattery` | 支持状态、循环、容量、Condition、充电 |
| 安全与锁定 | `SPHardwareDataType`、`profiles status`、`fdesetup status`、`csrutil status` | 当前 Activation Lock、MDM/ADE、FileVault、SIP;不证明服务器侧未来状态 |
| 存储 | `diskutil info -plist /`、`SPStorageDataType`、`SPNVMeDataType` | 容量、可用空间、文件系统、SMART/NVMe 可见健康 |
| 网络与蓝牙 | `SPAirPortDataType`、`SPBluetoothDataType` | 控制器存在、启用和连接状态;不保存 SSID/设备名 |
| 接口与外设 | USB、Thunderbolt、Display、Audio profiler | 当前枚举摘要;没有外设不代表所有物理接口通过 |

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · scripts/normalize.jxa (reported line 176)May include surrounding context.

text
| 设备 | `system_profiler SPHardwareDataType`、`ioreg IOPlatformExpertDevice`、`sw_vers` | 型号、芯片、内存、系统、序列号一致性 |
| 电池 | `system_profiler SPPowerDataType`、`ioreg AppleSmartBattery` | 支持状态、循环、容量、Condition、充电 |
| 安全与锁定 | `SPHardwareDataType`、`profiles status`、`fdesetup status`、`csrutil status` | 当前 Activation Lock、MDM/ADE、FileVault、SIP;不证明服务器侧未来状态 |
| 存储 | `diskutil info -plist /`、`SPStorageDataType`、`SPNVMeDataType` | 容量、可用空间、文件系统、SMART/NVMe 可见健康 |
| 网络与蓝牙 | `SPAirPortDataType`、`SPBluetoothDataType` | 控制器存在、启用和连接状态;不保存 SSID/设备名 |
| 接口与外设 | USB、Thunderbolt、Display、Audio profiler | 当前枚举摘要;没有外设不代表所有物理接口通过 |

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · scripts/normalize.jxa (reported line 177)May include surrounding context.

text
| 设备 | `system_profiler SPHardwareDataType`、`ioreg IOPlatformExpertDevice`、`sw_vers` | 型号、芯片、内存、系统、序列号一致性 |
| 电池 | `system_profiler SPPowerDataType`、`ioreg AppleSmartBattery` | 支持状态、循环、容量、Condition、充电 |
| 安全与锁定 | `SPHardwareDataType`、`profiles status`、`fdesetup status`、`csrutil status` | 当前 Activation Lock、MDM/ADE、FileVault、SIP;不证明服务器侧未来状态 |
| 存储 | `diskutil info -plist /`、`SPStorageDataType`、`SPNVMeDataType` | 容量、可用空间、文件系统、SMART/NVMe 可见健康 |
| 网络与蓝牙 | `SPAirPortDataType`、`SPBluetoothDataType` | 控制器存在、启用和连接状态;不保存 SSID/设备名 |
| 接口与外设 | USB、Thunderbolt、Display、Audio profiler | 当前枚举摘要;没有外设不代表所有物理接口通过 |

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · scripts/normalize.jxa (reported line 178)May include surrounding context.

text
| 设备 | `system_profiler SPHardwareDataType`、`ioreg IOPlatformExpertDevice`、`sw_vers` | 型号、芯片、内存、系统、序列号一致性 |
| 电池 | `system_profiler SPPowerDataType`、`ioreg AppleSmartBattery` | 支持状态、循环、容量、Condition、充电 |
| 安全与锁定 | `SPHardwareDataType`、`profiles status`、`fdesetup status`、`csrutil status` | 当前 Activation Lock、MDM/ADE、FileVault、SIP;不证明服务器侧未来状态 |
| 存储 | `diskutil info -plist /`、`SPStorageDataType`、`SPNVMeDataType` | 容量、可用空间、文件系统、SMART/NVMe 可见健康 |
| 网络与蓝牙 | `SPAirPortDataType`、`SPBluetoothDataType` | 控制器存在、启用和连接状态;不保存 SSID/设备名 |
| 接口与外设 | USB、Thunderbolt、Display、Audio profiler | 当前枚举摘要;没有外设不代表所有物理接口通过 |

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · scripts/normalize.jxa (reported line 179)May include surrounding context.

text
| 设备 | `system_profiler SPHardwareDataType`、`ioreg IOPlatformExpertDevice`、`sw_vers` | 型号、芯片、内存、系统、序列号一致性 |
| 电池 | `system_profiler SPPowerDataType`、`ioreg AppleSmartBattery` | 支持状态、循环、容量、Condition、充电 |
| 安全与锁定 | `SPHardwareDataType`、`profiles status`、`fdesetup status`、`csrutil status` | 当前 Activation Lock、MDM/ADE、FileVault、SIP;不证明服务器侧未来状态 |
| 存储 | `diskutil info -plist /`、`SPStorageDataType`、`SPNVMeDataType` | 容量、可用空间、文件系统、SMART/NVMe 可见健康 |
| 网络与蓝牙 | `SPAirPortDataType`、`SPBluetoothDataType` | 控制器存在、启用和连接状态;不保存 SSID/设备名 |
| 接口与外设 | USB、Thunderbolt、Display、Audio profiler | 当前枚举摘要;没有外设不代表所有物理接口通过 |

Static analysis

No suspicious patterns detected.