Back to skill

Security audit

Feishu Room Booking 3.2.0

Security checks for vulnerabilities and agentic risk

Overview

This appears to be a real Feishu meeting-room helper, but it should be reviewed because it can read calendar details, store workplace data locally, and automatically book rooms without confirmation in some flows.

Install only if you are comfortable granting the agent current-user Feishu calendar access, including attendee reads and calendar/resource writes. Before using automatic rebooking or waitlist polling, require explicit user opt-in and review generated local JSON files because they may contain employee IDs, meeting summaries, room choices, event IDs, and workplace-location history.

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/manage_preferences.py:37
Finding

Plaintext Storage of Sensitive Employee, Location, and Calendar Metadata

Content
View full analysis

Vulnerability Details

File Locations:

  • scripts/manage_preferences.py:37-39
  • scripts/manage_preferences.py:45-54
  • scripts/manage_preferences.py:84-93
  • scripts/watch_waitlist.py:57-59
  • scripts/watch_waitlist.py:88-100
  • scripts/workspace_manager.py:38-41

Vulnerability Type: Sensitive data stored in plaintext with process-default file permissions
Risk Level: Medium

Vulnerable Code

scripts/manage_preferences.py:37-39:

python
def save_prefs(data):
    with open(PREFS_FILE, "w", encoding="utf-8") as f:
        json.dump(data, f, ensure_ascii=False, indent=2)

scripts/manage_preferences.py:45-54:

python
prefs[user_id] = {
    "default_building": args.building or "",
    "capacity_gte": args.capacity_gte or 0,
    "capacity_lte": args.capacity_lte or 999,
    "preferred_rooms": [r.strip() for r in args.preferred_rooms.split(",")] if args.preferred_rooms else [],
    "note": args.note or "",
    "selection_history": prefs.get(user_id, {}).get("selection_history", [])
}
save_prefs(data)

scripts/manage_preferences.py:84-93:

python
history = user_prefs.setdefault("selection_history", [])
history.append({
    "room": room_name,
    "building": building_name,
    "time": __import__("datetime").datetime.now().isoformat()
})
# Retain only the latest 20 entries
user_prefs["selection_history"] = history[-20:]

scripts/watch_waitlist.py:57-59:

python
def save_waitlist(data: WaitlistData) -> None:
    with open(WAITLIST_FILE, "w", encoding="utf-8") as f:
        json.dump(data, f, ensure_ascii=False, indent=2)

scripts/watch_waitlist.py:88-100:

python
pending.append({
    "event_id": event_id,
    "summary": args.summary or "",
    "start": args.start,
    "end": args.end,
    "building": args.building or "",
    "capacity_gte": args.capacity_gte or 0,
    "attempted_rooms": [],
    "atte
...[truncated 3016 chars]
Remediation
View remediation

Remediation Suggestions

  1. Move mutable state out of the Skill package and into a per-user application-data directory.
  2. Create the state directory with mode 0700 and each state file with mode 0600, independent of the process umask.
  3. Use atomic writes through a temporary owner-only file followed by os.replace to prevent partial writes and unsafe permission transitions.
  4. Separate records by authenticated user or tenant instead of aggregating all users in one preference file.
  5. Enforce authorization before reading, listing, modifying, or deleting another user's records.
  6. Minimize retained data. Avoid storing meeting summaries, stable event identifiers, notes, or precise location history unless operationally necessary.
  7. Define retention periods and automatically purge expired waitlist entries and old room-selection or workspace history.
  8. Where the local threat model requires protection from filesystem disclosure, encrypt sensitive fields using an OS keyring or a tenant-scoped key stored outside the project directory.
  9. Document the sensitivity and lifecycle of all generated files and ensure backups and logs apply equivalent access controls.
Vulnerability Patterns
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (23)

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding

声明描述的是一个覆盖查询、预订、配置、导入、偏好、候补和时间线的完整技能;但该代码块的核心和几乎全部实际行为都集中在“查询会议室忙闲”上。已实现部分包括:楼栋/楼层/房间关键词解析、容量筛选、列出楼栋/会议室、读取用户偏好和工区默认值、并发查询 freebusy。虽然这些与声明中的“查询忙闲、筛选、偏好管理的一部分”相符,但声明中的多个关键能力——尤其是预订、补订、导入、候补轮询、时间线——在此代码块中并未体现。代码还会访问本地 mapping/preferences/workspace 配置和调用 lark-cli 的 freebusy 接口,这与会议室查询场景一致,不构成额外越权;问题在于声明明显高估了该代码块的能力范围。因此应判定为描述与代码行为存在实质不匹配。

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
92% confidence
Finding

声明描述的是一个完整的会议室查询与预订技能,但给出的代码块实际只覆盖“首次安装配置/导入会议室配置”这一部分。代码会根据公司名选择内置或自定义目录,支持从事件 JSON 或通过 lark-cli 拉取日程参与人,提取 resource 类型 attendee 中的 omm_ room_id,合并到本地 references/custom-room-mapping.json,并输出配置状态。它没有任何查询会议室忙闲、筛选可用会议室、创建预订、补订、偏好管理、候补轮询或工区时间线逻辑。因此代码行为与宣称的整体技能能力存在明显落差,属于描述覆盖范围远大于实际代码能力的失配。

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

声明描述的主功能是“会议室管理”,而代码的主功能是“工区(workspace/building)时间线与偏好管理”。代码仅操作本地 references/weekly-workspace.json 和 user-preferences.json,围绕工区设置、下周工区推荐、时间线展示、提醒检查等展开,没有任何飞书 API、日程读取、room_id 导入、会议室空闲查询、预订或补订逻辑。虽然声明中提到‘工区时间线’,与代码有部分交集,但这只是声明中的次要子项,无法覆盖代码整体与会议室技能之间的明显用途偏差。因此描述不能准确代表该代码行为,属于实质性不匹配。

Content

No source excerpt is available for this finding.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 18)May include surrounding context.

md
- 数据文件:内置目录 `references/room-mapping.json`、自定义目录 `references/custom-room-mapping.json`、租户配置 `references/tenant-profile.json`,以及偏好/候补/工区文件

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 153)May include surrounding context.

md
- 数据文件:内置目录 `references/room-mapping.json`、自定义目录 `references/custom-room-mapping.json`、租户配置 `references/tenant-profile.json`,以及偏好/候补/工区文件

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
96% confidence
Finding

The skill explicitly instructs the agent to use shell commands, read/write local reference files, and invoke external tooling (lark-cli and Python scripts), but it declares no permissions or allowed-tools scope. This creates an overprivileged and under-documented execution model where a host agent may permit broader filesystem or shell access than users expect, increasing the blast radius of prompt injection or operator mistakes.

Content

No source excerpt is available for this finding.

Ssd 3

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The skill explicitly directs automated scanning of near-term calendar events and attendee details, then persistence of that data as JSON for later processing, without requiring user confirmation for the automated path. Persisting sensitive calendar data locally expands exposure beyond live API access: it creates a secondary data store that may be retained, misused by other processes, or accessed via unrelated filesystem weaknesses.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The skill instructs the agent to scan the user's upcoming calendar and attendee details, but the top-level description does not clearly warn that it will read potentially sensitive event metadata and participant information. In a corporate environment, calendar titles, times, attendees, and room assignments can reveal confidential projects, relationships, and operational patterns.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill authorizes automatic room booking and waitlist-triggered booking without user confirmation in some flows. Because these actions write to the user's calendar and reserve shared corporate resources, lack of an explicit risk notice and consent checkpoint can cause unintended bookings, scheduling conflicts, and abuse if the skill is triggered incorrectly or manipulated by ambiguous input.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

This finding is a true vulnerability because the building alias is just "F11", which is far too generic and can easily collide with ordinary user references to a floor or room name. In a meeting-room booking skill, ambiguous building resolution can cause the agent to query, recommend, or book the wrong room in the wrong building, creating integrity and operational risks rather than direct code execution risk.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

This is also a true vulnerability because the alias is just "F4", a highly ambiguous token that is likely to appear in many normal room references across the dataset. Given the skill’s purpose of resolving natural-language meeting room requests into concrete room_id values, such a broad alias increases the chance of incorrect building selection and unintended room booking actions.

Content

No source excerpt is available for this finding.

Dynamic import via __import__()

Medium
Category
Dangerous Code Execution
Confidence
75% confidence
Finding

Dynamic import() can load arbitrary modules at runtime, bypassing static analysis and potentially importing malicious code.

Content

Scanner excerpt · scripts/manage_preferences.py (reported line 93)May include surrounding context.

python
history.append({
        "room": room_name,
        "building": building_name,
        "time": __import__("datetime").datetime.now().isoformat()
    })
    # 只保留最近 20 条
    user_prefs["selection_history"] = history[-20:]

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The --list operation prints all users' meeting-room preferences, including user identifiers, preferred rooms, and building preferences, without any access control, warning, or minimization. In a multi-user or shared-admin environment, this can expose behavioral and workplace-location data that may be sensitive and facilitate profiling of employees.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The delete_preference() function irreversibly removes a user's stored preference entry and immediately saves the modified file. There is no confirmation prompt, dry-run mode, or explicit warning to the user before this destructive action is performed.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

This code file contains natural-language documentation and user-visible output entirely in Chinese, including the top-level docstring and command help context. Under the policy rule for language/locale, forcing a specific language without opt-in is a violation unless the tool clearly documents a justified region-specific constraint, which is not present here.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/query_rooms.py (reported line 315)May include surrounding context.

python
})
    ]
    try:
        result = subprocess.run(cmd, capture_output=True, text=True, timeout=15)
        if result.returncode != 0:
            return {"status": "error", "busy_periods": []}
        data = json.loads(result.stdout)

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

This code file contains natural-language strings for errors, help text, and status messages exclusively in Chinese, such as the validation error at L054 and multiple argparse/help outputs through L259. Under the policy, forcing a specific language without user opt-in is a natural-language policy violation unless the locale constraint is clearly documented and justified, which is not present here.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/room_setup.py (reported line 139)May include surrounding context.

python
def fetch_event_resources(calendar_id: str, event_id: str) -> Any:
    process = subprocess.run(
        [
            "lark-cli", "calendar", "event.attendees", "list",
            "--calendar-id", calendar_id,

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

This code file contains natural-language documentation entirely in Chinese, including the module docstring and later user-facing CLI output, but provides no option to select another language or explanation that the skill is intentionally China-region-specific. That matches the policy concern for forcing a specific language without user opt-in.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

This is a natural-language policy issue because the file forces a specific language/locale in its docstring and CLI help context without user opt-in. The same pattern continues throughout user-facing strings, making the skill effectively inaccessible to users who are not expecting Chinese output.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/watch_waitlist.py (reported line 222)May include surrounding context.

python
cmd.extend(["--capacity-gte", str(cap_gte)])

        try:
            result = subprocess.run(cmd, capture_output=True, text=True, timeout=120)
            if result.returncode != 0:
                print(f"   ❌ 查询失败: {result.stderr}")
                item["attempts"] = item.get("attempts", 0) + 1

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

This code file contains natural-language usage instructions and output strings that assume Chinese as the only supported language. Under the policy, forcing a specific language without user choice is a natural-language policy violation unless the locale constraint is explicitly justified.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
92% confidence
Finding

The module docstring, help text, and user-facing output are all in Chinese, with no option to select another language and no indication that the tool is intentionally limited to a Chinese-speaking context. This is a natural-language locale constraint that is not presented as an opt-in or justified region-specific requirement.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.