Back to skill

Security audit

Kiro Realtime Chat

Security checks for vulnerabilities and agentic risk

Overview

This is a disclosed local chat helper for trusted Kiro instances, with ordinary shared-file risks users should understand before sharing sensitive messages.

Install only if the participating Kiro instances are in the same trusted local workspace. Do not use this channel for secrets or high-stakes instructions unless you add file permissions, authentication or sender verification, and locking or atomic writes to prevent spoofing, message suppression, and lost updates.

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 (2)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/read_messages.py:14
Finding
Unauthenticated Participant Identity Enables Message Disclosure, Spoofing, and Suppression## Vulnerability Details **File Location**: `scripts/read_messages.py:14-30, 34-35`; `scripts/send_message.py:11-31, 35-39` **Vulnerability Type**: Missing authentication and authorization **Risk Level**: Medium ### Vulnerable Code `scripts/read_messages.py:14-30`: ```python def read_messages(my_name, mark_read=True): if not os.path.exists(CHAT_FILE): print("📭 No messages yet") return [] with open(CHAT_FILE, "r") as f: chat = json.load(f) # Update last check time chat["lastCheck"] = datetime.now().isoformat() # Filter unread messages for me my_messages = [] for msg in chat["messages"]: if msg["to"] == my_name and not msg["read"]: my_messages.append(msg) if mark_read: msg["read"] = True # Save read status with open(CHAT_FILE, "w") as f: json.dump(chat, f, indent=2) return my_messages ``` `scripts/read_messages.py:34-35`: ```python my_name = sys.argv[1] messages = read_messages(my_name) ``` `scripts/send_message.py:11-31`: ```python def send_message(from_name, to_name, message): # Load or create chat file if os.path.exists(CHAT_FILE): with open(CHAT_FILE, "r") as f: chat = json.load(f) else: chat = {"messages": [], "lastCheck": datetime.now().isoformat()} # Add new message msg_id = len(chat["messages"]) + 1 chat["messages"].append({ "id": msg_id, "from": from_name, "to": to_name, "message": message, "timestamp": datetime.now().isoformat(), "read": False }) # Save os.makedirs(os.path.dirname(CHAT_FILE), exist_ok=True) with open(CHAT_FILE, "w") as f: json.dump(chat, f, indent=2) ``` `scripts/send_message.py:35-39`: ```python from_name = sys.argv[1] to_n ...[truncated 2382 chars]
Remediation
## Remediation Suggestions 1. Replace caller-provided display names as identity credentials with authenticated participant identities. 2. Issue each participant a protected credential or use operating-system-backed identity and access controls. 3. Authorize every read operation against the authenticated recipient rather than an arbitrary `my_name` argument. 4. Cryptographically sign messages or protect the store with authenticated IPC so recipients can verify sender identity and message integrity. 5. Separate participant mailboxes and apply restrictive permissions where participants do not fully trust one another. 6. Create the workspace directory and chat file with owner-only permissions, such as directory mode `0700` and file mode `0600`, where compatible with the intended sharing model. 7. Avoid marking messages as read until the authenticated recipient has successfully processed them. Consider explicit acknowledgement identifiers. 8. Document that, without participant isolation, all processes with access to the shared file belong to the same trust boundary.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/send_message.py:12
Finding
Non-Atomic Read-Modify-Write Operations Permit Message Loss and JSON Corruption## Vulnerability Details **File Location**: `scripts/send_message.py:12-31`; `scripts/read_messages.py:14-30` **Vulnerability Type**: Race condition and unsafe file update **Risk Level**: Medium ### Vulnerable Code `scripts/send_message.py:12-31`: ```python # Load or create chat file if os.path.exists(CHAT_FILE): with open(CHAT_FILE, "r") as f: chat = json.load(f) else: chat = {"messages": [], "lastCheck": datetime.now().isoformat()} # Add new message msg_id = len(chat["messages"]) + 1 chat["messages"].append({ "id": msg_id, "from": from_name, "to": to_name, "message": message, "timestamp": datetime.now().isoformat(), "read": False }) # Save os.makedirs(os.path.dirname(CHAT_FILE), exist_ok=True) with open(CHAT_FILE, "w") as f: json.dump(chat, f, indent=2) ``` `scripts/read_messages.py:14-30`: ```python def read_messages(my_name, mark_read=True): if not os.path.exists(CHAT_FILE): print("📭 No messages yet") return [] with open(CHAT_FILE, "r") as f: chat = json.load(f) # Update last check time chat["lastCheck"] = datetime.now().isoformat() # Filter unread messages for me my_messages = [] for msg in chat["messages"]: if msg["to"] == my_name and not msg["read"]: my_messages.append(msg) if mark_read: msg["read"] = True # Save read status with open(CHAT_FILE, "w") as f: json.dump(chat, f, indent=2) return my_messages ``` ### Technical Analysis Both scripts perform a shared-file read-modify-write transaction without inter-process locking. The destination is opened using mode `"w"`, which truncates it before serialization finishes, and no temporary-file-plus-atomic-replacemen ...[truncated 2021 chars]
Remediation
## Remediation Suggestions 1. Protect the entire read-modify-write transaction with an inter-process lock. The lock must cover loading, mutation, and persistence rather than only the write operation. 2. Write serialized data to a temporary file in the same directory, flush it, call `fsync` where durability matters, and atomically replace the destination with `os.replace`. 3. Ensure the temporary file has restrictive permissions and is created safely with a non-predictable name. 4. Replace sequential IDs derived from list length with collision-resistant identifiers such as UUIDs. 5. Handle malformed or interrupted JSON safely, including controlled recovery from a validated backup rather than silently overwriting data. 6. Prefer a transactional data store such as SQLite for concurrent clients. Use transactions and appropriate locking or write-ahead logging. 7. Add concurrency tests covering simultaneous sends, simultaneous reads, and a send concurrent with a read-status update.
Vulnerability Patterns
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (4)

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The skill instructs multiple instances to exchange messages through a shared JSON file but does not mention any confidentiality, integrity, locking, or access-control safeguards. This can expose message contents to unauthorized readers, allow tampering or spoofed messages by other local actors, and cause corruption or race conditions when multiple writers update the file concurrently.

Intent-Code Divergence

Medium
Confidence
93% confidence
Finding
The top-level docstring describes a read-oriented operation: 'Check and read messages for a specific Kiro'. In practice, the function mutates the chat store by updating `lastCheck` and, by default, setting matching messages' `read` flag to `True`, then writes the file back to disk.

Natural-Language Policy Violations

Low
Confidence
76% confidence
Finding
The example payload uses the message `Selam!`, which implicitly sets a non-default language context without offering a language choice or explaining a locale-specific purpose. Even though it is only an example, this is natural-language content in the skill file and can conflict with organizational language/locale neutrality expectations.

Missing User Warnings

Low
Confidence
88% confidence
Finding
This code performs file writes that change persistent state by updating `lastCheck` and marking messages as read, then saves the JSON file. Although the script prints message status, it does not clearly disclose to the user that running it will mutate the underlying chat file rather than only reading it.

Static analysis

No suspicious patterns detected.