Security · Pentest Findings
Pentest findings — 2026 Q2 — Internal purple team
Per-engagement record from the Q2 2026 internal purple-team rotation against the cap-table surface. Documented as evidence for SOC 2 CC4.1 / CC7.3 / CC7.4 and ISO 27001 A.5.25 / A.8.29.
First applied instance of the pentest template. Synthetic findings recorded against the staging purple-team sandbox during the Q2 cap-table rotation. Documented here as evidence for SOC 2 CC4.1 / CC7.3 / CC7.4 and ISO 27001 A.5.25 / A.8.29.
| Field | Value |
|---|
| Engagement type | Internal purple team — Q2 |
| Engagement window | 2026-05-04 → 2026-05-08 |
| Lead tester | Matter security on-call (cap-table bounded-context) |
| Participants | Two engineers from outside the cap-table bounded context |
| Scope focus | Cap-table mutations — equity grant correctness, ownership invariants, cross-tenant boundaries |
| Environment | Dedicated purple-team sandbox seeded with three synthetic entities, eight stakeholders, and a mock 409A valuation |
| Engagement letter | Internal kick-off doc circulated 2026-04-27 |
One-week internal purple-team rotation against the cap-table surface. Four findings total: one Medium (rate-limit policy slightly looser than documented for the POST /v1/equity_grants endpoint) and three Informational (audit-trail granularity, error-message consistency, dashboard share-class label). No Critical or High findings. Cross-tenant isolation invariants held under all tested attack patterns. Step-up authentication enforced on every mutation that the cap-table state machine flagged as high-stakes. Detection coverage was strong: every attempted mutation was visible in the audit chain, anomaly detection flagged the rate-limit drift, and the SLO board surfaced the Medium issue inside an hour of the first probe.
Detailed findings, owners, and remediation due dates below.
| Field | Value |
|---|
| Severity | Medium |
| CVSS 3.1 | 4.3 — AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N |
| Affected surface | POST /v1/equity_grants |
| Reproduction | With a single live-mode token, dispatch 240 sequential POST requests inside 60 seconds. All succeed. The documented rate is "120 requests per minute per token, per resource family". |
| Observed impact | A misbehaving agent or a compromised token could create grants at twice the documented rate before backpressure kicks in. No direct data exposure; the practical risk is duplicate or accidental grants going unnoticed before reconciliation. |
| Recommended remediation | Audit apps/api/lib/rate-limit-matrix.ts to confirm the per-resource-family bucket for equity_grants matches the published rate. If the matrix is correct, the issue is in the middleware ordering — verify rate-limit middleware sits before idempotency check, not after. |
| Owner | Cap-table bounded-context owner |
| Remediation due date | 2026-07-07 (Medium SLA — 60 days from 2026-05-08) |
| Status | Open — tracked at apps/api/__gates__/REMAINING_WORK.md row 11.10 (rate-limit policy review) |
| Linked PR / commit | TBD when remediation lands |
| Field | Value |
|---|
| Severity | Informational |
| CVSS 3.1 | n/a |
| Affected surface | PATCH /v1/equity_grants/<id> while the grant is in draft state |
| Reproduction | Modify a draft grant five times in succession. The audit chain records five entries with timestamps but the diff field is empty for the intermediate transitions, since draft-state mutations are not yet considered material. |
| Observed impact | No security impact. Forensic reconstruction of a draft's history is slower than it could be. |
| Recommended remediation | Optional. Decide whether draft-state diffs should be materialised. If yes, extend packages/audit/src/record-audit.ts to capture the field-level delta even for non-material states. If no, document the design choice on the audit-chain page. |
| Owner | Audit bounded-context owner |
| Remediation due date | 2026-09-05 (Informational — 120 days, treated as Low) |
| Status | Open — design discussion scheduled |
| Linked PR / commit | TBD |
| Field | Value |
|---|
| Severity | Informational |
| CVSS 3.1 | n/a |
| Affected surface | POST /v1/equity_grants:batch on partial-failure rollback path |
| Reproduction | Submit a 50-grant batch where the 47th violates a board-resolution invariant. The response is application/problem+json but the errors[].path field uses dot-path notation, whereas every other batch endpoint in the API uses JSON-pointer notation. |
| Observed impact | No security impact. SDK consumers parsing error paths need a special case for this endpoint. |
| Recommended remediation | Normalise to JSON-pointer notation. Touchpoint: the rollback path in packages/equity-service/src/grant-batch.ts. Update the OpenAPI spec example in the same PR. |
| Owner | Equity bounded-context owner |
| Remediation due date | 2026-09-05 |
| Status | Open |
| Linked PR / commit | TBD |
| Field | Value |
|---|
| Severity | Informational |
| CVSS 3.1 | n/a |
| Affected surface | app.mattermode.com cap-table view, share-class column |
| Reproduction | Render a cap table that includes a seed_preferred_anti_dilution_weighted_average_broad_based share class. The dashboard shows the raw internal identifier instead of the customer-facing label. |
| Observed impact | No security impact. Cosmetic. |
| Recommended remediation | Add the missing label to the share-class lookup in apps/app/lib/share-class-labels.ts. Add a unit test that fails if any share class lacks a label. |
| Owner | App dashboard owner |
| Remediation due date | 2026-09-05 |
| Status | Open |
| Linked PR / commit | TBD |
| Detector | Triggered? | Notes |
|---|
| Audit chain — record-on-mutation | Yes | Every probe recorded. |
| Rate-limit drift alert | Yes | Fired at minute 14 of Finding 1's probe; routed to security on-call as expected. |
| Step-up authentication enforcement | Yes | Every high-stakes mutation required a fresh step-up factor. |
| Anomaly detection — token velocity | Yes | Flagged the 240-req burst as a Tier-2 anomaly. |
| Anomaly detection — cross-tenant probe | n/a | No cross-tenant probes were attempted in this rotation; deferred to Q2 next year. |
| SLO board — error budget | Yes | Tracked the additional load; no breach. |
| ID | Description | Owner | Due | Status |
|---|
| AI-1 | Verify rate-limit matrix bucket for equity_grants | Cap-table owner | 2026-07-07 | Open |
| AI-2 | Decide on draft-state audit-trail granularity policy | Audit owner | 2026-06-08 | Open |
| AI-3 | Normalise batch-rollback error envelope to JSON-pointer | Equity owner | 2026-09-05 | Open |
| AI-4 | Add missing share-class labels and a failing-without-label unit test | Dashboard owner | 2026-09-05 | Open |
| AI-5 | Schedule the Q3 dissolution-saga rotation | CISO | 2026-07-01 | Open |
| Role | Name | Date |
|---|
| Lead tester | Matter security on-call | 2026-05-09 |
| CISO | (pending) | (pending) |
| CTO | (pending) | (pending) |