From 71b6e9c88868489f87855111dfa0d84c6b7f5e38 Mon Sep 17 00:00:00 2001 From: Benedict Balogun <50557035+wolfyres@users.noreply.github.com> Date: Mon, 27 Jul 2026 22:44:30 +0100 Subject: [PATCH 1/8] Create SECURITY.md --- tools/v1/team/shared-team-inbox/SECURITY.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 tools/v1/team/shared-team-inbox/SECURITY.md diff --git a/tools/v1/team/shared-team-inbox/SECURITY.md b/tools/v1/team/shared-team-inbox/SECURITY.md new file mode 100644 index 000000000..ee18f5eba --- /dev/null +++ b/tools/v1/team/shared-team-inbox/SECURITY.md @@ -0,0 +1,16 @@ +# Threat Model & Safety Assumptions: Shared Team Inbox (V1) + +## 1. Threat Assumptions & Vectors + +| Threat Vector | Source | Impact | Mitigation Strategy | +| :--- | :--- | :--- | :--- | +| **XSS / HTML Injection** | Malicious email body / headers | Execution of arbitrary JavaScript in team context | Strict HTML sanitization; stripping dangerous tags (` World'; + expect(sanitizeMessageBody(hostile)).toBe('Hello [REDACTED SCRIPT] World'); + }); + + it('strips event handlers and javascript URIs', () => { + const hostile = 'Click me'; + const sanitized = sanitizeMessageBody(hostile); + expect(sanitized).not.toContain('onclick'); + expect(sanitized).not.toContain('javascript:'); + }); + + it('sanitizes malicious filenames', () => { + expect(sanitizeFilename('../../../etc/passwd')).toBe('.._.._.._etc_passwd'); + }); + }); + + describe('Performance Safeguards', () => { + it('enforces maximum pagination bounds of 50 items', () => { + const dummyList = Array.from({ length: 120 }, (_, i) => ({ + id: `msg-${i}`, + teamId: 'team-1', + sender: 'test@example.com', + subject: `Subj ${i}`, + body: 'Body', + timestamp: Date.now(), + attachments: [], + })); + + const page1 = paginateInboxMessages(dummyList, 1, 100); // requested 100 + expect(page1.items.length).toBe(50); // bounded to max 50 + expect(page1.hasMore).toBe(true); + }); + + it('truncates bodies exceeding character limits', () => { + const hugeBody = 'A'.repeat(150000); + const { text, isTruncated } = truncateLargeBody(hugeBody, 100000); + expect(isTruncated).toBe(true); + expect(text).toContain('[Content truncated for performance size limit]'); + }); + }); +});