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

Content
View full analysis

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
View 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

Content
View full analysis

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
View 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
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.