Email rackctl@gmail.com with subject [security][digest-pipeline]. Do not open public issues for security reports.
Acknowledgement target: within 72 hours. Triage target: within 5 business days.
digest-pipeline aggregates cross-team activity, drafts a weekly newsletter with Claude via Bedrock, and sends it through SES. It touches people's names, work items, and messages, so its defining controls are PII never reaches the model unfiltered and nothing sends without a human approving it.
- Every aggregated item is passed through
sanitizeSourceItem(src/pipeline/filters/pii.ts) before it leaves its aggregator. Sanitization is enforced by a type brand: the LLM prompt builder only acceptsSanitizedSourceItem[](src/pipeline/types.ts), so unredactedSourceItems can't reach the generator — the compiler rejects it. - The regex scrubber covers compensation, performance/HR, contact info, health, HR case IDs, SSN, credit card, and DOB classes.
assertNoPii(src/pipeline/filters/pii.ts) runs at two checkpoints: post-aggregation (after the pre-LLM PII filter) and post-LLM (on generated draft text), so a leak in the model output is caught before the draft is persisted or sent.
- No draft is ever sent to SES without an explicit human approval. The approver allow-list is
read from AWS Secrets Manager (the
APPROVERS_SECRET_IDsecret:{cosUserId, backupApproverIds[]}) — it is not hardcoded and not editable from the UI. - The approve action is the only path to
POST /drafts/:id/approve → SES send. An unapproved draft expires; expiry, edit deltas, approval timestamps, and send receipts all land as immutableaudit_eventsrows keyed onrun_id.
- Every API route except
/healthis gated by WorkOS JWT auth —josevalidates the bearer token against the WorkOS JWKS (src/api/). The web review UI authenticates with WorkOS AuthKit; its proxy routes carry the JWT through to the API. - Identities in aggregated content are resolved through WorkOS Directory Sync
(
src/pipeline/identity/workos.ts) — the pipeline acts on directory-known users.
- No long-lived credentials in the app. Pods get AWS access via EKS Pod Identity; there
are no static keys anywhere in the repo or image. Bedrock, S3, SES, and Secrets Manager calls
run as the
<env>-digest-pipeline-tenantrole, vended to the pod by the Pod Identity agent. - App-level secrets are projected at deploy time by External Secrets Operator from AWS Secrets
Manager (
digest-pipeline/<env>/*) into a Kubernetes Secret consumedenvFrom— never committed. - Inference runs on-account via Amazon Bedrock — source content is not sent to third parties.
- Default-deny
NetworkPolicywith an explicit egress allow-list: DNS, HTTPS to AWS APIs and the GitHub / Linear / Notion / Slack / WorkOS endpoints, and Postgres on the cluster VPC CIDR. Ingress is limited to the VPC range the ALB's network interfaces sit in reaching the web tier, plus intra-pod web → api traffic. The api Deployment takes nothing from outside the release. IMDS is blocked. - Public surface is the review UI only. Everything under the host goes to web, behind an ALB that terminates TLS against an ACM certificate and redirects plaintext to HTTPS. The api is ClusterIP-only and reached server-side by web's route handlers.
- PII redaction is regex-class-based. A novel sensitive-data shape not covered by an existing
class can pass the pre-LLM filter; the post-LLM
assertNoPiicheckpoint is the backstop, and new classes land insrc/pipeline/filters/pii.tswith a test (see CONTRIBUTING.md). - The approval gate trusts the allow-list in Secrets Manager. Rotating an approver out of the org is enforced on the next run's secret read, not retroactively on an in-flight draft.
- Approval freshness is bounded by WorkOS Directory Sync propagation — an identity change upstream is reflected on the next pipeline run, not mid-draft.
digest-pipeline exposes the controls needed for SOC 2 Type II — Pod-Identity-only access with no
static credentials, secrets sourced from AWS Secrets Manager (never committed), PII scrubbing
enforced at the type boundary before inference, a complete per-run audit trail in the
immutable audit_events ledger, and a human approval gate before any external send. Substrate-
level controls (CIS EKS baseline, Pod Security Standards, image signing) are enforced upstream
by landing-zone and eks-gitops.