T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/okki-sync.js:397
- Finding
- Outgoing email synchronization can associate sensitive content with the wrong CRM customer<![CDATA[ ## Vulnerability Details **File Location**: `scripts/okki-sync.js`, lines 397-401 **Vulnerability Type**: Incorrect customer identity selection **Risk Level**: High ### Vulnerable Code ```javascript const customer = await matchCustomer( emailData.from || emailData.to, emailData.subject, emailData.body ); ``` The selected customer is subsequently used to create the CRM trail: ```javascript const trailResult = await createEmailTrail(customer.company_id, { ...emailData, uid: emailData.uid }); ``` The trail includes message metadata and content: ```javascript const content = `${directionLabel}\n` + `主题:${emailData.subject}\n` + `时间:${emailData.date}\n` + `发件人:${emailData.from}\n` + `收件人:${emailData.to}\n` + `摘要:${emailData.body ? emailData.body.substring(0, 200) : '(无内容)'}${attachmentList}`; ``` ### Technical Analysis `syncEmailToOkki` always prefers `emailData.from` whenever it is present. It does not consider `emailData.direction`. For an inbound email, the sender may correctly identify the customer. For an outbound email, however, `from` normally contains the local employee or organization address, while the external customer is identified by `to`. The documented integration supplies both fields and sets `direction: 'out'`, but the implementation does not use that direction when selecting the address for customer matching. Once the wrong address is selected, its domain or vector-search result determines the CRM company. The module then creates a trail under that company containing: - The email subject - Sender and recipient addresses - The first 200 characters of the message body - Attachment filenames - The message date and direction This is an authorization-boundary failure at the data-association layer: data intended for one customer can be written into another customer's CRM record. ### Attack Path 1. An outbound message is sent with the local organization's address in `from` and the intended customer in `to`. 2. Th ...[truncated 1237 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions Select the external party according to the message direction: ```javascript const customerAddress = emailData.direction === 'out' ? emailData.to : emailData.from; if (!customerAddress) { return { success: false, reason: 'missing_customer_address', message: 'Unable to determine the external customer address' }; } const customer = await matchCustomer( customerAddress, emailData.subject, emailData.body ); ``` Additional hardening should include: 1. Parse and normalize mailbox structures instead of assuming `from` and `to` are single plain strings. 2. For outbound messages with multiple recipients, require an explicit policy rather than assigning all content to the first inferred customer. 3. Exclude known internal domains from customer matching. 4. Refuse synchronization when both endpoints are internal or when the external party is ambiguous. 5. Verify that the selected CRM company corresponds to the intended external address before creating a trail. 6. Add tests for inbound, outbound, internal-only, multiple-recipient, and malformed-address cases. 7. Minimize trail content where possible, particularly body excerpts and attachment names. ]]>
