T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/send_line_oa_chat.py:75
- Finding
- Substring Recipient Matching Can Send Messages to an Unintended Chat## Vulnerability Details **File Location**: `scripts/send_line_oa_chat.py`, lines 75-92 **Vulnerability Type**: Improper recipient validation caused by substring matching **Risk Level**: Medium ### Vulnerable Code ```python def unique_chat_result(page: Page, recipient: str, timeout_ms: int) -> Locator: # `exact=True` prevents matching the unrelated "輸入搜尋內容" field. search = page.get_by_placeholder("搜尋", exact=True) search.fill(recipient) page.wait_for_timeout(min(timeout_ms, 1000)) # The chat label can be hidden on responsive layouts. Its anchor remains clickable. results = page.locator("mark").filter(has_text=recipient).locator("xpath=ancestor::a") deadline = time.monotonic() + timeout_ms / 1000 while results.count() == 0 and time.monotonic() < deadline: page.wait_for_timeout(200) count = results.count() if count != 1: raise RuntimeError( f"Recipient search for {recipient!r} returned {count} chat candidates; " "do not guess when the recipient is ambiguous." ) return results.first ``` ### Technical Analysis The Skill declares that a message must be sent to an exact, explicitly authorized recipient. However, the result locator uses Playwright's `filter(has_text=recipient)`, which performs text containment rather than exact equality. The code only verifies that one candidate contains the requested text. It does not verify that the complete displayed chat name equals the authorized recipient. Consequently, a unique partial match is treated as an exact match. The `exact=True` argument applies only to locating the search input placeholder and does not make the chat-result comparison exact. ### Attack Path 1. The user authorizes a message to a recipient named `Alice`. 2. The script enters `Alice` in the LINE chat search field. 3. The result set contains one chat named `Alice Support`, but no chat whose complete name is `Alice`. 4. `has_text="Alice"` matches the `Alice ...[truncated 851 chars]
- Remediation
- ## Remediation Suggestions 1. Read the complete displayed recipient label from each result and compare it with the requested recipient using exact equality. 2. Normalize only explicitly accepted presentation differences, such as leading or trailing whitespace. Do not silently apply substring, fuzzy, or case-insensitive matching unless that behavior is separately authorized. 3. Verify the selected chat header again after navigation and before filling or submitting the message. 4. Abort if the exact recipient is absent, even when there is only one partial search result. 5. Add automated tests covering: - A single exact match. - A single partial match such as `Alice Support` for `Alice`. - Multiple partial matches. - Duplicate exact display names. - Names that differ only by whitespace or case. 6. Return a stable identifier or validated chat metadata from the selection function rather than relying only on a text-containing anchor. A hardened pattern should conceptually enforce: ```python candidates = results.all() exact_matches = [ candidate for candidate in candidates if candidate.inner_text().strip() == recipient.strip() ] if len(exact_matches) != 1: raise RuntimeError("Expected exactly one exact recipient match") ``` The exact DOM element containing the authoritative chat name should be used instead of comparing all text within the anchor.
