diff --git a/README.md b/README.md
index 9173529..9e87d52 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,7 @@
# Specifications
+## Protocol Specifications
+
* [Endpoints](./endpoints.md)
* [HTTP API](./http_api.md)
* [ETS registry format](./registry-v1.md) (Deprecated)
@@ -10,6 +12,10 @@
* [purl (Package URL) format](./package-url.md)
+## Security
+
+ * [Security Documentation](./security/README.md) - Threat model, SDLC, operations, supply chain, compliance
+
## Repositories and mirrors
To host a repository only the [Repository endpoint](./endpoints.md#repository) has to be implemented.
diff --git a/security/README.md b/security/README.md
new file mode 100644
index 0000000..ced0d2c
--- /dev/null
+++ b/security/README.md
@@ -0,0 +1,58 @@
+# Security Documentation
+
+This documentation describes the security model, practices, and controls for the Hex package ecosystem.
+
+## Overview
+
+Hex.pm is a package registry for the Erlang and Elixir ecosystem. It enables publishing, discovery, and consumption of packages used in production systems. This documentation covers:
+
+- What we protect and what can go wrong (threat model)
+- How we build and release software securely (SDLC)
+- How we operate and respond to incidents (operations)
+- How we ensure package integrity (supply chain)
+
+## Documentation Structure
+
+### [Threat Model](./threat-model/overview.md)
+
+Analysis of assets, actors, threats, and mitigations.
+
+- [Overview](./threat-model/overview.md) - Scope and methodology
+- [Architecture](./threat-model/architecture.md) - System overview and trust boundaries
+- [Assets](./threat-model/assets.md) - What we protect
+- [Actors](./threat-model/actors.md) - Legitimate users and adversaries
+- [Threats](./threat-model/threats.md) - Key threats to the ecosystem
+- [Mitigations](./threat-model/mitigations.md) - How threats are addressed
+- [Assumptions](./threat-model/assumptions.md) - What we assume and don't guarantee
+
+### [Secure Development Lifecycle](./sdlc/README.md)
+
+How we build and maintain secure software, organized into three pillars.
+
+- [Overview](./sdlc/README.md) - SDLC structure and registers
+- [Secure Build](./sdlc/build.md) - Artifact provenance, dependencies, toolchain
+- [Secure Process](./sdlc/process.md) - Code review, QA, security scanning, vulnerability handling
+- [Secure Runtime](./sdlc/runtime.md) - Deployment, secrets, monitoring
+- [Risk Register](./sdlc/risk-register.md) - Accepted risks and mitigations
+- [Exception Register](./sdlc/exception-register.md) - Approved policy deviations
+
+### [Operations](./operations/incident-response.md)
+
+How we operate and respond to security events.
+
+- [Incident Response](./operations/incident-response.md) - Triage, response, notification
+- [Access Control](./operations/access-control.md) - Internal access principles
+
+### [Supply Chain Security](./supply-chain/overview.md)
+
+How we ensure package integrity from publish to install.
+
+- [Overview](./supply-chain/overview.md) - Supply chain security approach
+- [Provenance](./supply-chain/provenance.md) - Build origin and attestations
+- [Signing](./supply-chain/signing.md) - Registry signing and checksums
+- [Verification](./supply-chain/verification.md) - Client-side verification
+
+## Related Documentation
+
+- [Client Flows](./threat-model/client-flows.md) - Authentication and verification flows
+- [Endpoints](../endpoints.md) - API and repository endpoints
diff --git a/security/operations/access-control.md b/security/operations/access-control.md
new file mode 100644
index 0000000..81f3974
--- /dev/null
+++ b/security/operations/access-control.md
@@ -0,0 +1,55 @@
+# Access Control
+
+This document describes access control for Hex infrastructure.
+
+## Application Access Levels
+
+### Public Access
+
+- Package downloads (public packages)
+- Registry metadata
+- Documentation viewing
+
+### Authenticated User Access
+
+- Publishing packages (own packages)
+- Managing account settings
+- Viewing private packages (with permission)
+
+### Organization Admin Access
+
+- Managing organization members
+- Configuring private repositories
+- Billing management
+
+### Operator Access
+
+- Infrastructure administration
+- Incident response
+- Policy enforcement
+
+## Infrastructure Access
+
+### Production Systems
+
+A small number of operators have access to production infrastructure.
+Access is logged via GCP Cloud Logging and GKE audit logs.
+
+### Cloud Provider Access
+
+- Application repository CI/CD uses OIDC workload identity federation (no long-lived service account keys)
+- Infrastructure repository CI/CD uses a long-lived GCP service account key stored as a GitHub Actions secret, scoped per environment
+- Kubernetes access controlled via RBAC
+- Infrastructure changes applied via CI pipeline
+
+### Database Access
+
+- Direct production database access restricted to operators
+- Application accesses database via dedicated service credentials
+
+## Audit
+
+### Logging
+
+- GKE and infrastructure events logged to GCP Cloud Logging
+- Application-level audit log for security-relevant actions (publish, ownership changes, etc.)
diff --git a/security/operations/incident-response.md b/security/operations/incident-response.md
new file mode 100644
index 0000000..7430e95
--- /dev/null
+++ b/security/operations/incident-response.md
@@ -0,0 +1,96 @@
+# Incident Response
+
+This document describes incident response procedures for the Hex ecosystem.
+
+## Incident Classification
+
+### Severity Levels
+
+| Level | Description | Examples |
+|-------|-------------|----------|
+| Critical | Active exploitation, widespread impact | Registry compromise, malicious package spreading |
+| High | Significant risk, limited exploitation | Account takeovers, targeted attacks |
+| Medium | Potential risk, no active exploitation | Vulnerability discovered, suspicious activity |
+| Low | Minor issues, minimal impact | Policy violations, minor misconfigurations |
+
+## Response Procedures
+
+### Detection
+
+- Monitoring alerts
+- User reports
+- Security researcher reports
+- Automated scanning
+
+### Triage
+
+1. Assess severity and scope
+2. Identify affected systems/users
+3. Determine response urgency
+4. Assign incident owner
+
+### Containment
+
+- Revoke compromised credentials
+- Disable affected accounts (if necessary)
+- Block malicious packages
+- Isolate affected systems
+
+### Eradication
+
+- Remove malicious content
+- Patch vulnerabilities
+- Reset compromised credentials
+- Verify no persistence mechanisms
+
+### Recovery
+
+- Restore normal operations
+- Monitor for recurrence
+- Communicate with affected users
+
+### Post-Incident
+
+- Document incident timeline
+- Identify root cause
+- Implement preventive measures
+- Update procedures as needed
+
+## Communication
+
+### Internal
+
+- Incident channel for coordination
+- Regular status updates
+- Clear ownership and escalation
+
+### External
+
+- User notification when affected
+- Public disclosure when appropriate
+- Coordinate with reporters
+
+## Specific Scenarios
+
+### Compromised Maintainer Account
+
+1. Disable account access
+2. Revoke all tokens
+3. Review recent publishing activity
+4. Contact maintainer via verified channel
+5. Consider retiring suspicious versions
+
+### Malicious Package
+
+1. Mark package/version as retired
+2. Notify users who downloaded recently
+3. Investigate publishing account
+4. Document for community awareness
+
+### Infrastructure Compromise
+
+1. Isolate affected systems
+2. Assess scope of access
+3. Rotate all credentials
+4. Rebuild from known-good state
+5. Full security audit
diff --git a/security/sdlc/README.md b/security/sdlc/README.md
new file mode 100644
index 0000000..a363ff6
--- /dev/null
+++ b/security/sdlc/README.md
@@ -0,0 +1,47 @@
+# Secure Development Lifecycle
+
+This documentation describes the secure development practices for Hex registry
+infrastructure, organized into three pillars.
+
+## Pillars
+
+### [Secure Build](./build.md)
+
+How we build software securely:
+
+- Artifact provenance and integrity
+- Dependency management and constraints
+- Toolchain security (CI/CD, compilers, formatters)
+
+### [Secure Process](./process.md)
+
+How we develop software securely:
+
+- Code review requirements
+- Quality assurance and testing
+- Security scanning
+- Vulnerability handling and disclosure
+
+### [Secure Runtime](./runtime.md)
+
+How we run software securely:
+
+- Deployment controls
+- Secrets management
+- Service ownership
+- Monitoring and observability
+
+## Registers
+
+### [Risk Register](./risk-register.md)
+
+Tracked security risks with their severity, status, and mitigations.
+
+### [Exception Register](./exception-register.md)
+
+Approved deviations from security policies with justification and expiry.
+
+## Related Documentation
+
+- [Supply Chain Security](../supply-chain/overview.md) - Package integrity from publish to install
+- [Operations](../operations/incident-response.md) - Incident response and access control
diff --git a/security/sdlc/build.md b/security/sdlc/build.md
new file mode 100644
index 0000000..5efe567
--- /dev/null
+++ b/security/sdlc/build.md
@@ -0,0 +1,105 @@
+# Secure Build
+
+This document describes secure build practices for Hex registry infrastructure.
+
+## Artifact Provenance
+
+### Docker Images
+
+| Property | Implementation |
+|----------|----------------|
+| Image digest | SHA256 of image manifest |
+| Push by digest | Ensures immutability |
+| Multi-platform manifests | Consistent across architectures |
+| Git commit linking | Image tagged with short SHA |
+
+### Image Tagging
+
+| Tag Format | Example | Purpose |
+|------------|---------|---------|
+| Short SHA | `abc1234` | Identifies specific commit |
+| Registry | `gcr.io/hexpm-prod/hexpm` | GCP Container Registry |
+
+### Package Releases
+
+| Property | Implementation |
+|----------|----------------|
+| Checksums | SHA-256 in signed registry |
+| Immutability | Cannot modify after grace period |
+| Registry signing | RSA-PKCS1-SHA512 signatures |
+
+## Dependencies
+
+### Automated Updates
+
+Most Hex projects use GitHub Dependabot for automated dependency updates:
+
+| Repository | Dependabot | Ecosystems |
+|------------|------------|------------|
+| hexpm/hexpm | Yes | github-actions, mix |
+| hexpm/hex | Yes | github-actions, mix |
+| hexpm/hex_core | Yes | github-actions, rebar |
+| hexpm/hex_solver | Yes | github-actions, mix |
+| hexpm/hexdocs | Yes | github-actions, mix |
+| hexpm/preview | Yes | github-actions, mix |
+| hexpm/diff | Yes | github-actions, mix |
+| hexpm/specifications | Yes | github-actions |
+| hexpm/bob | No | - |
+| hexpm/hexdocs-search | No | - |
+
+### Dependency Constraints
+
+Some projects have restrictions on external dependencies:
+
+| Project | Constraint | Reason |
+|---------|------------|--------|
+| hex | No external deps | Bootstrapped before package manager available |
+| hex_core | No external deps | Designed to be vendored by clients |
+
+These projects must only use OTP standard library functions or vendor library code.
+
+### Dependency Selection
+
+| Criterion | Consideration |
+|-----------|---------------|
+| Maintenance status | Active development and releases |
+| Security track record | History of vulnerabilities and response |
+| Community adoption | Usage and community support |
+| License compatibility | Apache 2.0 / MIT preferred |
+
+### Minimization Principles
+
+| Principle | Implementation |
+|-----------|----------------|
+| Prefer standard library | Use OTP/Elixir stdlib when sufficient |
+| Avoid unnecessary deps | Each dependency adds attack surface |
+| Evaluate transitives | Consider full dependency tree |
+
+## Toolchain
+
+### CI Pipeline
+
+| Check | Description |
+|-------|-------------|
+| Formatting | Code formatting enforced in CI |
+| Unit tests | Automated tests run on every PR |
+| CodeQL | Security scanning for GitHub Actions workflows |
+| Zizmor | GitHub Actions security best practices |
+
+### Authentication (CI)
+
+Application repositories (`hexpm/hexpm`, `hexpm/hex`, `hexpm/preview`, `hexpm/diff`, `hexpm/hexdocs`) authenticate to GCP using Workload Identity Federation:
+
+| Stage | Method |
+|-------|--------|
+| GCP authentication | Workload Identity Federation (OIDC) |
+| Container Registry | Short-lived OAuth2 access token from OIDC |
+| Image build / push | No long-lived service account keys in repo secrets |
+
+The infrastructure repository (`hexpm/hexpm-ops`) authenticates to GCP using a long-lived service account key stored as a GitHub Actions secret, scoped per environment.
+
+## Related Documentation
+
+- [Secure Process](./process.md) - Code review and quality assurance
+- [Secure Runtime](./runtime.md) - Deployment and operations
+- [Supply Chain - Signing](../supply-chain/signing.md) - Registry signing
diff --git a/security/sdlc/exception-register.md b/security/sdlc/exception-register.md
new file mode 100644
index 0000000..74073bb
--- /dev/null
+++ b/security/sdlc/exception-register.md
@@ -0,0 +1,39 @@
+# Exception Register
+
+This document tracks approved deviations from security policies for Hex registry infrastructure.
+
+## Active Exceptions
+
+| ID | Exception | Justification | Approved By | Expiry | Review Date |
+|----|-----------|---------------|-------------|--------|-------------|
+| - | - | - | - | - | - |
+
+## Exception Process
+
+### Requesting an Exception
+
+1. Document the specific policy deviation required
+2. Provide justification explaining why the exception is necessary
+3. Describe compensating controls or mitigations in place
+4. Propose an expiry date or review cadence
+
+### Approval Criteria
+
+| Criterion | Description |
+|-----------|-------------|
+| Business justification | Clear need for the exception |
+| Risk assessment | Understanding of security impact |
+| Compensating controls | Mitigations to reduce risk |
+| Time-bound | Defined expiry or review date |
+
+### Review Process
+
+- Exceptions are reviewed on their specified review date
+- Expired exceptions must be renewed or the deviation corrected
+- All active exceptions are reviewed during security audits
+
+## Archived Exceptions
+
+| ID | Exception | Expiry | Resolution |
+|----|-----------|--------|------------|
+| - | - | - | - |
diff --git a/security/sdlc/process.md b/security/sdlc/process.md
new file mode 100644
index 0000000..ef36dd2
--- /dev/null
+++ b/security/sdlc/process.md
@@ -0,0 +1,131 @@
+# Secure Process
+
+This document describes secure development process practices for Hex registry infrastructure.
+
+## Code Review
+
+### Requirements
+
+Code review requirements are enforced through GitHub rulesets. See the repository rulesets for the authoritative configuration.
+
+| Repository | Status |
+|------------|--------|
+| hexpm/hexpm | Active |
+| hexpm/hex | Active |
+| hexpm/hex_core | Active |
+| hexpm/hex_solver | Active |
+| hexpm/hexdocs | Active |
+| hexpm/preview | Active |
+| hexpm/diff | Active |
+| hexpm/specifications | Active |
+| hexpm/bob | None |
+| hexpm/hexdocs-search | None |
+
+### Ruleset Configuration (hexpm)
+
+| Rule | Configuration |
+|------|---------------|
+| CodeQL | All security alerts, all general alerts |
+| Zizmor | All security alerts, all general alerts |
+| Code quality | All severity levels enforced |
+| Bypass | No bypass permissions configured |
+
+### Security Considerations
+
+Reviewers evaluate:
+
+- Authentication and authorization boundaries
+- Input validation at trust boundaries
+- Output encoding to prevent injection
+- Cryptographic usage
+- Secrets handling
+
+## Quality Assurance
+
+### Testing
+
+| Test Type | Coverage | Notes |
+|-----------|----------|-------|
+| Unit tests | All projects | Required for changes |
+| Integration tests | Hex client against hexpm | Matrix across Hex versions |
+| Property-based tests | hex_core | `proper` framework |
+
+### Compatibility Testing
+
+Projects are tested against:
+
+- All [supported OTP versions](https://github.com/erlang/otp/security#supported-versions)
+- All [supported Elixir versions](https://hexdocs.pm/elixir/compatibility-and-deprecations.html)
+- Erlang/OTP master and Elixir main to catch bugs early
+
+### Hex Client Integration
+
+The Hex client is integration tested against the hexpm registry.
+
+### CI Gates
+
+| Check | Enforcement |
+|-------|-------------|
+| All CI checks pass | Required |
+| CodeQL security scan | Required |
+| Zizmor workflow scan | Required |
+| Code review | Required |
+
+## Security Scanning
+
+### Automated Scanners
+
+| Scanner | Trigger | Scope |
+|---------|---------|-------|
+| CodeQL | Push/PR to main, weekly | GitHub Actions |
+| Zizmor | Push/PR to main, weekly | Workflow security |
+
+### Vulnerability Sources
+
+We collaborate with the [Erlang Ecosystem Foundation CNA](https://cna.erlef.org/) for BEAM ecosystem CVEs.
+
+### Vulnerability Response
+
+| Severity | Response |
+|----------|----------|
+| Critical / High | Out-of-band release |
+| Medium / Low | Normal update cycle |
+
+## Vulnerability Handling
+
+- [Hex.pm security policy](https://github.com/hexpm/hexpm/security/policy)
+- [EEF CNA security policy](https://cna.erlef.org/security-policy)
+
+## Secure Coding Practices
+
+### Input Validation
+
+| Boundary | Validation |
+|----------|------------|
+| API endpoints | Parameter validation |
+| Package uploads | Format and size validation |
+| User input | Sanitization before storage |
+
+### Database Security
+
+| Practice | Implementation |
+|----------|----------------|
+| Parameterized queries | Ecto (no raw SQL) |
+| Connection pooling | Postgrex with TLS |
+| Schema validation | Ecto changesets |
+
+### Authentication
+
+| Feature | Implementation |
+|---------|----------------|
+| Password hashing | bcrypt |
+| TOTP 2FA | `pot` library |
+| OAuth2 | `ueberauth` + GitHub |
+| Session management | Phoenix sessions |
+
+## Related Documentation
+
+- [Secure Build](./build.md) - Build pipeline and dependencies
+- [Secure Runtime](./runtime.md) - Deployment and operations
+- [EEF CNA Security Policy](https://cna.erlef.org/security-policy.html) - Full disclosure policy
+- [Operations - Incident Response](../operations/incident-response.md) - Incident handling
diff --git a/security/sdlc/risk-register.md b/security/sdlc/risk-register.md
new file mode 100644
index 0000000..85691d6
--- /dev/null
+++ b/security/sdlc/risk-register.md
@@ -0,0 +1,43 @@
+# Risk Register
+
+This document tracks accepted security risks and their mitigations for Hex registry infrastructure.
+
+## Active Risks
+
+| ID | Risk | Severity | Status | Threats | Mitigation | Reference |
+|----|------|----------|--------|---------|------------|-----------|
+| R-001 | Basic Authentication maintained for backward compatibility | Medium | Mitigating | [T4](../threat-model/threats.md#t4-account-takeover) | OAuth2 migration planned; rate limiting in place | Security Audit 2026 |
+| R-002 | Documentation hosted as full websites (HTML/JS) | Low | Accepted | [T5](../threat-model/threats.md#t5-documentation-based-attacks) | Malicious content removed upon report | Security Audit 2026 |
+| R-003 | User enumeration via API | Low | Accepted | [T4](../threat-model/threats.md#t4-account-takeover) | Users are public for package publication; profile info is user-provided | Security Audit 2026 |
+| R-004 | No WAF | Low | Accepted | [T6](../threat-model/threats.md#t6-registry-infrastructure-compromise) | SQL injection prevented by Ecto; XSS prevented by CSP; little added value expected | Security Audit 2026 |
+
+## Risk Assessment Criteria
+
+### Severity Levels
+
+| Level | Description |
+|-------|-------------|
+| Critical | Immediate threat to core infrastructure or user data |
+| High | Significant security impact requiring prioritized remediation |
+| Medium | Moderate security impact with acceptable short-term risk |
+| Low | Minor security consideration with minimal impact |
+
+### Status Definitions
+
+| Status | Description |
+|--------|-------------|
+| Accepted | Risk acknowledged and accepted with mitigations |
+| Mitigating | Active work to reduce risk |
+| Resolved | Risk eliminated or reduced to acceptable level |
+
+## Review Process
+
+- Risks are reviewed quarterly or when significant changes occur
+- New risks identified during security audits are added to this register
+- Resolved risks are moved to the archive section below
+
+## Archived Risks
+
+| ID | Risk | Resolution Date | Resolution |
+|----|------|-----------------|------------|
+| - | - | - | - |
diff --git a/security/sdlc/runtime.md b/security/sdlc/runtime.md
new file mode 100644
index 0000000..27ffb8c
--- /dev/null
+++ b/security/sdlc/runtime.md
@@ -0,0 +1,82 @@
+# Secure Runtime
+
+This document describes secure runtime practices for Hex registry infrastructure.
+
+## Deployment Controls
+
+Deployments are triggered via a Slack bot by authorized operators. The bot
+initiates a CI pipeline (GitHub Actions) that builds Docker images and applies
+Kubernetes manifests. Deployments are only automatically applied from the `main`
+branch; other branches are validated but not deployed. The bot monitors rollout
+progress (pod readiness) in real time and reports status back to Slack.
+Rollbacks are performed manually by redeploying a previous commit via the same
+mechanism. Concurrency controls prevent simultaneous deployments to the same
+environment.
+
+## Secrets Management
+
+### In Development
+
+| Practice | Status |
+|----------|--------|
+| No secrets in source code | Enforced |
+| Environment-based configuration | Implemented |
+| Separate credentials per environment | Implemented |
+
+### In CI/CD
+
+| Secret | Storage | Access |
+|--------|---------|--------|
+| GCP service account (application repos) | None in repo secrets | OIDC workload identity |
+| GCP service account (infrastructure repo) | GitHub secrets (long-lived JSON key) | Direct credential, scoped per environment |
+| Database credentials | Runtime secrets | Production only |
+
+### Production
+
+| Aspect | Implementation |
+|--------|----------------|
+| Secrets storage | Encrypted with GCP KMS, stored in infrastructure config |
+| Application repo CI access | OIDC workload identity federation (no long-lived keys) |
+| Infrastructure repo CI access | Long-lived service account key in GitHub Actions secrets, scoped per environment |
+| Environment isolation | Separate credentials for staging and production |
+
+## Service Ownership
+
+### Response Team
+
+Incident response roles:
+
+| Role | Responsibility |
+|------|----------------|
+| Security lead | Triage and coordination |
+| Development | Fix implementation |
+| Operations | Deployment and monitoring |
+
+## Monitoring
+
+### Health and Availability
+
+| Activity | Purpose |
+|----------|---------|
+| Health checks | Verify service availability |
+| Uptime monitoring | Track service availability |
+
+### Error Tracking
+
+| Activity | Purpose |
+|----------|---------|
+| Error monitoring | Sentry integration |
+| Alerting | Notification on anomalies |
+
+### Metrics
+
+| Activity | Purpose |
+|----------|---------|
+| Telemetry | Performance and usage metrics |
+| Logging | Audit trail and debugging |
+
+## Related Documentation
+
+- [Secure Build](./build.md) - Build pipeline and dependencies
+- [Secure Process](./process.md) - Code review and quality assurance
+- [Operations - Incident Response](../operations/incident-response.md) - Incident handling
diff --git a/security/supply-chain/overview.md b/security/supply-chain/overview.md
new file mode 100644
index 0000000..fede6ac
--- /dev/null
+++ b/security/supply-chain/overview.md
@@ -0,0 +1,93 @@
+# Supply Chain Security Overview
+
+This document describes the supply chain security approach for the Hex ecosystem.
+
+## What is Supply Chain Security?
+
+Supply chain security ensures that:
+
+1. **Provenance** - You know where software came from
+2. **Integrity** - Software hasn't been tampered with
+3. **Verification** - Claims can be cryptographically verified
+
+## Hex Supply Chain Model
+
+```mermaid
+flowchart LR
+ subgraph Maintainer["Maintainer Environment"]
+ Build["Build & Package"]
+ end
+
+ subgraph Registry["hex.pm"]
+ API["API"]
+ Sign["Sign & Store"]
+ end
+
+ subgraph Distribution["repo.hex.pm (CDN/S3)"]
+ Dist["Distribute"]
+ end
+
+ subgraph Consumer["Client Environment"]
+ Verify["Verify & Install"]
+ end
+
+ Build --> API
+ API --> Sign
+ Sign --> Dist
+ Dist --> Verify
+```
+
+## Security Properties
+
+### Publishing Side
+
+| Property | Description | Status |
+|----------|-------------|--------|
+| Authentication | Publishing requires authenticated user | Implemented |
+| Authorization | Only owners can publish to their packages | Implemented |
+| Audit logging | All publishing actions are logged | Implemented |
+| Owner notifications | All package owners are notified by email when a new version is published or when owners are added or removed | Implemented |
+| 2FA for publishing | OTP required for write operations via OAuth | Implemented |
+| Trusted publishing (OIDC) | Short-lived CI credentials | Planned |
+| Build provenance (SLSA) | Cryptographic proof of build origin | Planned |
+
+### Distribution Side
+
+| Property | Description | Status |
+|----------|-------------|--------|
+| Signed registry | Metadata signed with RSA-PKCS1-SHA512 | Implemented |
+| Checksums | Artifacts have SHA-256 checksums | Implemented |
+| Immutability | Versions cannot be modified after grace period | Implemented |
+| Transparency log | Append-only log of publication events | Planned |
+
+### Consumption Side
+
+| Property | Description | Status |
+|----------|-------------|--------|
+| Signature verification | Clients verify registry signatures | Implemented |
+| Checksum verification | Clients verify artifact checksums | Implemented |
+| Lock files | Exact versions recorded for reproducibility | Implemented |
+| Provenance verification | Clients verify build attestations | Planned |
+
+## Attack Surface
+
+| Stage | Threats | Current Mitigations |
+|-------|---------|---------------------|
+| Maintainer | Compromised credentials, malicious insider | 2FA, OAuth, audit logs |
+| Build | Compromised build environment | None (planned: trusted publishing, SLSA provenance) |
+| Publishing | Unauthorized publish, tampering | Authentication, authorization |
+| Distribution | CDN/mirror tampering, MITM | Signed registry, checksums |
+| Consumption | Dependency confusion, typosquatting | Repository field verification, typosquatting detection |
+
+## Detailed Documentation
+
+- [Provenance](./provenance.md) - Build origin and attestations
+- [Signing](./signing.md) - Registry signing and checksums
+- [Verification](./verification.md) - Client-side verification
+
+## Related Specifications
+
+- [Client Flows](../threat-model/client-flows.md) - Detailed client interaction flows
+- [Registry v2](../../registry-v2.md) - Signed registry format
+- [Package Tarball](../../package_tarball.md) - Checksum format
+
diff --git a/security/supply-chain/provenance.md b/security/supply-chain/provenance.md
new file mode 100644
index 0000000..5dec736
--- /dev/null
+++ b/security/supply-chain/provenance.md
@@ -0,0 +1,107 @@
+# Provenance
+
+This document describes package provenance in the Hex ecosystem.
+
+## What is Provenance?
+
+Provenance answers:
+
+- **Who** published this package?
+- **When** was it published?
+- **Where** was it built?
+- **How** was it built?
+
+## Current State
+
+### What We Track
+
+| Attribute | Tracked | Verifiable | Notes |
+|-----------|---------|------------|-------|
+| Publishing user | Yes | Via audit log | Account that initiated publish |
+| Publish timestamp | Yes | Via API | Stored on the release record and exposed via the HTTP API; not part of the signed registry |
+| Publishing IP/client | Yes | Via audit log | Internal only |
+| Source repository | Yes | Metadata only | Maintainer-provided, not verified |
+| Build environment | No | No | Planned with SLSA provenance |
+| Build commands | No | No | Planned with SLSA provenance |
+
+### Limitations
+
+- No cryptographic proof of build origin
+- Source link is maintainer-provided metadata (not verified)
+- Build environment is not attested
+- No way to verify package was built from claimed source
+
+## Planned Improvements
+
+### Trusted Publishing (OIDC)
+
+| Feature | Description | Status |
+|---------|-------------|--------|
+| GitHub Actions | OIDC-based publishing from GitHub CI | Planned |
+| GitLab CI | OIDC-based publishing from GitLab | Planned |
+| Other providers | Extensible OIDC provider support | Future |
+
+Benefits:
+- No long-lived secrets needed in CI
+- Verifiable link to source repository
+- Repository-bound publishing authority
+
+### SLSA Build Provenance
+
+SLSA (Supply-chain Levels for Software Artifacts) provenance provides
+attestations about the build process. The SLSA Build track has three levels:
+
+| SLSA Build Level | Requirements | Focus |
+|------------------|--------------|-------|
+| L1 | Provenance showing how the package was built | Mistakes, documentation |
+| L2 | Signed provenance, generated by a hosted build platform | Tampering after the build |
+| L3 | Hardened build platform | Tampering during the build |
+
+Hex does not mandate a specific SLSA level. Instead, Hex plans to accept and
+validate build provenance attestations at whatever level a package maintainer
+chooses to provide. This allows the ecosystem to adopt SLSA incrementally.
+
+| Feature | Status |
+|---------|--------|
+| Accept and validate SLSA provenance attestations | Planned |
+
+### Build Transparency Log
+
+All publication events will be recorded in an append-only transparency log:
+
+| Feature | Description |
+|---------|-------------|
+| Immutable log | Publication events cannot be modified |
+| Timestamping | Cryptographic proof of publication time |
+| Dual transparency | Sigstore/Rekor and SCITT receipts |
+| Public audit | Anyone can verify the log |
+
+## Trust Levels
+
+| Publishing Method | Trust Level | Verification Possible |
+|-------------------|-------------|----------------------|
+| Manual (API key) | Low | Account only |
+| OAuth with 2FA | Medium | Account + 2FA |
+| Trusted Publishing | High | Account + CI identity + repository |
+| SLSA Provenance | Highest | Full build chain verification |
+
+## Consumer Guidance
+
+### Current Best Practices
+
+- Check package metadata for source links
+- Verify maintainer reputation
+- Review source code for critical dependencies
+- Pin exact versions in lock files
+
+### Future Capabilities
+
+- Verify SLSA provenance attestations
+- Require minimum provenance level via policy
+- Automated policy enforcement in CI
+- Query transparency log for package history
+
+## Related Documentation
+
+- [Signing](./signing.md) - Registry signing mechanisms
+- [Verification](./verification.md) - Client-side verification
diff --git a/security/supply-chain/signing.md b/security/supply-chain/signing.md
new file mode 100644
index 0000000..b52346a
--- /dev/null
+++ b/security/supply-chain/signing.md
@@ -0,0 +1,158 @@
+# Signing
+
+This document describes cryptographic signing in the Hex ecosystem.
+
+## Registry Signing
+
+### What is Signed
+
+All registry files are signed:
+
+| File | Description |
+|------|-------------|
+| `/names` | List of package names |
+| `/versions` | All package versions |
+| `/packages/{name}` | Per-package metadata |
+
+### Signature Format
+
+Registry files use a [`Signed` protobuf wrapper](../../registry/signed.proto).
+See [Registry v2](../../registry-v2.md) for full specification.
+
+### Algorithm
+
+| Parameter | Value |
+|-----------|-------|
+| Signature algorithm | RSA-PKCS1-SHA512 |
+| Key size | 2048 bits |
+| Payload | Raw protobuf bytes (before signing) |
+
+### Public Key Distribution
+
+The hex.pm public key is:
+
+- Hardcoded in official client libraries
+- Available at https://hex.pm/docs/public_keys
+- Should be verified out-of-band
+
+### Verification Process
+
+```mermaid
+sequenceDiagram
+ participant Client
+ participant CDN as repo.hex.pm
+
+ Client->>CDN: Fetch registry file (gzip)
+ CDN-->>Client: Compressed data
+ Client->>Client: Decompress
+ Client->>Client: Parse Signed protobuf
+ Client->>Client: Verify RSA-PKCS1-SHA512 signature
+ alt Signature valid
+ Client->>Client: Parse inner payload
+ Client->>Client: Verify repository field
+ else Signature invalid
+ Client->>Client: ABORT - possible tampering
+ end
+```
+
+See [Client Flows](../threat-model/client-flows.md#registry-verification) for
+detailed verification steps.
+
+## Package Checksums
+
+### Outer Checksum
+
+| Attribute | Value |
+|-----------|-------|
+| Algorithm | SHA-256 |
+| Input | Entire tarball file |
+| Storage | In signed registry metadata |
+| Verification | Before trusting tarball contents |
+
+### Inner Checksum (Legacy)
+
+| Attribute | Value |
+|-----------|-------|
+| Algorithm | SHA-256 |
+| Input | Concatenation of VERSION, metadata.config, contents.tar.gz |
+| Storage | CHECKSUM file inside tarball |
+| Status | Legacy - outer checksum is authoritative |
+
+See [Package Tarball](../../package_tarball.md) for format details.
+
+### Verification Process
+
+```mermaid
+sequenceDiagram
+ participant Client
+ participant CDN as repo.hex.pm
+ participant Registry as Signed Registry
+
+ Client->>Registry: Get outer_checksum
+ Client->>CDN: Download tarball
+ CDN-->>Client: Tarball bytes
+ Client->>Client: Compute SHA-256
+ alt Checksum matches
+ Client->>Client: Extract contents
+ else Checksum mismatch
+ Client->>Client: ABORT - possible tampering
+ end
+```
+
+## Trust Model
+
+### What Signing Provides
+
+| Property | Description |
+|----------|-------------|
+| Integrity | Detect tampering with registry/artifacts |
+| Authenticity | Confirm data came from hex.pm |
+| Freshness | Combined with caching headers |
+
+### What Signing Does NOT Provide
+
+| Property | Reason |
+|----------|--------|
+| Provenance | No proof of who built the package |
+| Safety | No guarantee package is safe to use |
+| Source verification | No link to source code |
+
+> [!CAUTION]
+> A valid signature only proves the artifact came from hex.pm. It does NOT prove
+> the package is safe, trustworthy, or built from the claimed source.
+
+## Key Management
+
+### Current State
+
+| Aspect | Status |
+|--------|--------|
+| Key count | Single signing key for all registry files |
+| Protection | Infrastructure security controls |
+| Rotation | Never performed; highly disruptive (breaks all clients until updated) |
+| Transparency | Key changes are implicitly visible |
+
+### Planned Improvements
+
+| Feature | Description | Status |
+|---------|-------------|--------|
+| Chain of trust | Offline root key signs operational signing keys | Future |
+
+## Future: Attestation Signing
+
+Beyond registry signing, future attestations (SLSA provenance, VEX, etc.) will use:
+
+| Technology | Purpose |
+|------------|---------|
+| Sigstore/Fulcio | Keyless signing with OIDC identity |
+| Sigstore/Rekor | Transparency log for attestations |
+| SCITT | Enterprise transparency receipts |
+| DSSE | Multi-signature envelope format |
+
+See [Provenance](./provenance.md) for details on planned attestation support.
+
+## Related Documentation
+
+- [Verification](./verification.md) - Client-side verification
+- [Registry v2](../../registry-v2.md) - Registry format specification
+- [Client Flows](../threat-model/client-flows.md) - Detailed verification flows
diff --git a/security/supply-chain/verification.md b/security/supply-chain/verification.md
new file mode 100644
index 0000000..64933e2
--- /dev/null
+++ b/security/supply-chain/verification.md
@@ -0,0 +1,171 @@
+# Verification
+
+This document describes client-side verification in the Hex ecosystem.
+
+## Overview
+
+Clients MUST verify integrity before trusting registry data or package contents.
+
+See [Client Flows](../threat-model/client-flows.md#verification-summary) for the authoritative specification.
+
+## Registry Verification
+
+All clients perform these steps:
+
+### Verification Steps
+
+| Step | Action | Failure Behavior |
+|------|--------|------------------|
+| 1. Decompress | Decompress gzip-compressed registry file | Error |
+| 2. Decode | Parse outer `Signed` protobuf | Error |
+| 3. Verify signature | RSA-PKCS1-SHA512 against hex.pm public key | **ABORT** |
+| 4. Verify repository | Check `repository` field matches expected | **ABORT** |
+| 5. Parse payload | Parse inner protobuf (Names, Versions, Package) | Error |
+
+> [!IMPORTANT]
+> Steps 3 and 4 are security-critical. Failure at these steps indicates possible tampering or cross-repository attacks.
+
+### Signature Verification Detail
+
+```mermaid
+flowchart TD
+ A[Fetch registry file] --> B[Decompress gzip]
+ B --> C[Parse Signed protobuf]
+ C --> D{Verify RSA-PKCS1-SHA512
signature}
+ D -->|Valid| E[Parse inner payload]
+ D -->|Invalid| F[ABORT - tampering detected]
+ E --> G{Repository field
matches?}
+ G -->|Yes| H[Trust data]
+ G -->|No| I[ABORT - cross-repo attack]
+```
+
+## Tarball Verification
+
+### Verification Steps
+
+| Step | Action | Failure Behavior |
+|------|--------|------------------|
+| 1. Download | Fetch from `/tarballs/{name}-{version}.tar` | Retry/error |
+| 2. Compute checksum | SHA-256 of entire tarball | Error |
+| 3. Compare | Check against `outer_checksum` from signed registry | **ABORT** |
+| 4. Extract | Extract: VERSION, metadata.config, contents.tar.gz, CHECKSUM | Error |
+| 5. Inner checksum | Verify CHECKSUM file (optional, legacy) | Warning |
+
+### Checksum Verification Detail
+
+```mermaid
+flowchart TD
+ A[Download tarball] --> B[Compute SHA-256]
+ B --> C{Matches outer_checksum
from registry?}
+ C -->|Yes| D[Extract contents]
+ C -->|No| E[ABORT - tampering detected]
+ D --> F{Check inner
CHECKSUM?}
+ F -->|Yes| G{Inner checksum
valid?}
+ F -->|No| H[Continue - outer is authoritative]
+ G -->|Yes| H
+ G -->|No| I[Warn - possible issue]
+```
+
+## Client Implementations
+
+| Client | Library | Language |
+|--------|---------|----------|
+| Mix (Elixir) | hex_core | Erlang |
+| Rebar3 (Erlang) | hex_core | Erlang |
+| Gleam | hexpm-rust | Rust |
+
+### Verification Code Locations
+
+| Client | Verification Module | Notes |
+|--------|---------------------|-------|
+| hex_core | `hex_repo` | Shared by Mix and Rebar3 |
+| hexpm-rust | `hexpm::repo` | Uses `ring` crate for crypto |
+
+## Error Handling
+
+### Signature Failure
+
+| Response | Action |
+|----------|--------|
+| Abort | Stop immediately |
+| Message | Security error - possible tampering |
+| Fallback | **NEVER** fall back to unverified data |
+
+### Checksum Mismatch
+
+| Response | Action |
+|----------|--------|
+| Abort | Stop immediately |
+| Message | Integrity error - possible tampering |
+| Fallback | **NEVER** use mismatched artifact |
+
+### Network Failure
+
+| Response | Action |
+|----------|--------|
+| Retry | Attempt retry with backoff |
+| Cache | May fall back to cached data (with warning) |
+| Reason | Cached data was verified when fetched |
+
+## Mirror Security
+
+### Trusted vs Untrusted Mirrors
+
+| Mirror Type | Credentials | Use Case |
+|-------------|-------------|----------|
+| Trusted | Can receive credentials | Organization-controlled mirrors |
+| Untrusted | **NEVER** send credentials | Community mirrors, public caches |
+
+### Untrusted Mirror Security
+
+> [!CAUTION]
+> When using untrusted mirrors:
+> - **NEVER** send credentials (API keys, tokens)
+> - **ALWAYS** verify signatures (signatures are from hex.pm, not mirror)
+> - Private packages MUST use trusted endpoints only
+
+```mermaid
+flowchart TD
+ A[Client] --> B{Mirror type?}
+ B -->|Trusted| C[Send credentials OK]
+ B -->|Untrusted| D[NO credentials]
+ C --> E[Fetch data]
+ D --> E
+ E --> F[Verify signature
against hex.pm key]
+ F -->|Valid| G[Use data]
+ F -->|Invalid| H[Reject]
+```
+
+## Public Key
+
+### Current Key
+
+| Attribute | Value |
+|-----------|-------|
+| Algorithm | RSA |
+| Key size | 2048 bits |
+| Usage | RSA-PKCS1-SHA512 signatures |
+| Distribution | Hardcoded in clients |
+| Availability | https://hex.pm/docs/public_keys |
+
+### Key Pinning
+
+> [!TIP]
+> For high-security environments, verify the public key out-of-band before first use. Compare the key in your client library against the key published at hex.pm.
+
+## Future: Attestation Verification
+
+Planned verification capabilities for SLSA provenance and other attestations:
+
+| Feature | Description | Status |
+|---------|-------------|--------|
+| SLSA provenance | Verify build attestations | Planned |
+| VEX verification | Verify vulnerability statements | Planned |
+| Transparency proofs | Verify inclusion in transparency log | Planned |
+| Policy enforcement | Require minimum provenance level | Planned |
+
+## Related Documentation
+
+- [Signing](./signing.md) - How signing works
+- [Client Flows](../threat-model/client-flows.md) - Detailed client flows
+- [Provenance](./provenance.md) - Build provenance and attestations
diff --git a/security/threat-model/actors.md b/security/threat-model/actors.md
new file mode 100644
index 0000000..9f0dceb
--- /dev/null
+++ b/security/threat-model/actors.md
@@ -0,0 +1,91 @@
+# Actors
+
+This document identifies the actors that interact with the Hex ecosystem.
+
+For how these actors interact with the system, see [Architecture](architecture.md).
+
+## Legitimate Actors
+
+### Package Consumer
+
+Developers and CI/CD systems that install and use packages.
+
+| Attribute | Description |
+|-----------|-------------|
+| Access | Unauthenticated read access to public packages; API key for private |
+| Trust level | Untrusted (no write access) |
+| Capabilities | Download packages, read registry metadata, view documentation |
+
+### Package Maintainer
+
+Developers who publish and manage packages. There are two ownership levels:
+
+- **Maintainer** — publish, retire/unretire releases, upload documentation
+- **Owner** — all maintainer capabilities, plus manage package ownership
+
+| Attribute | Description |
+|-----------|-------------|
+| Access | Authenticated API access, publishing permissions |
+| Trust level | Trusted for their own packages |
+
+### Organization Administrator
+
+Manages private repositories and teams within an organization.
+
+| Attribute | Description |
+|-----------|-------------|
+| Access | Elevated permissions within organization scope |
+| Trust level | Trusted for organization resources |
+| Capabilities | Manage members, configure billing, access private packages |
+
+### Hex.pm Operator
+
+Maintains and operates the registry infrastructure.
+
+| Attribute | Description |
+|-----------|-------------|
+| Access | Infrastructure and administrative access |
+| Trust level | Highly trusted |
+| Capabilities | System administration, incident response, policy enforcement |
+
+## Adversarial Actors
+
+### External Attacker
+
+| Attribute | Description |
+|-----------|-------------|
+| Goal | Compromise downstream systems via supply chain |
+| Access | No legitimate access |
+| Capabilities | Network attacks (MITM without TLS), social engineering, exploiting vulnerabilities |
+
+### Malicious Maintainer
+
+| Attribute | Description |
+|-----------|-------------|
+| Goal | Inject malicious code into packages |
+| Access | Legitimate publishing access to their own packages |
+| Capabilities | Publish malicious updates, typosquatting, dependency confusion attacks |
+
+### Compromised Maintainer
+
+| Attribute | Description |
+|-----------|-------------|
+| Goal | Attacker leverages stolen legitimate access |
+| Access | Stolen credentials or hijacked session |
+| Capabilities | All maintainer capabilities, potentially elevated privileges |
+
+### Supply Chain Attacker
+
+| Attribute | Description |
+|-----------|-------------|
+| Goal | Compromise build/release pipeline |
+| Access | Indirect via dependencies or tooling |
+| Capabilities | Compromise CI systems, tamper with build artifacts, inject backdoors via dependencies |
+
+### Insider Threat
+
+| Attribute | Description |
+|-----------|-------------|
+| Goal | Data theft, sabotage, or other malicious intent |
+| Access | Legitimate internal access (operator, employee) |
+| Capabilities | Depends on role; may bypass external controls |
diff --git a/security/threat-model/architecture.md b/security/threat-model/architecture.md
new file mode 100644
index 0000000..0eed36a
--- /dev/null
+++ b/security/threat-model/architecture.md
@@ -0,0 +1,342 @@
+# Architecture
+
+This document describes the system architecture from a security perspective. For detailed client interaction flows including authentication, verification, and caching, see [Client Flows](client-flows.md).
+
+## Ecosystem Inventory
+
+### Services
+
+| Name | Description | Production | Staging | Repository |
+|------|-------------|------------|---------|------------|
+| Hex Registry | Main registry, web UI & API | hex.pm | staging.hex.pm | [hexpm/hexpm](https://github.com/hexpm/hexpm) |
+| Hex Operations | Terraform, Config, Fastly Compute | - | - | [hexpm/hexpm-ops](https://github.com/hexpm/hexpm-ops) (private) |
+| Hex Docs | Documentation hosting | hexdocs.pm | staging.hexdocs.pm | [hexpm/hexdocs](https://github.com/hexpm/hexdocs), [hexpm/hexdocs-search](https://github.com/hexpm/hexdocs-search) |
+| Hex Preview | Package preview | preview.hex.pm | preview.staging.hex.pm | [hexpm/preview](https://github.com/hexpm/preview) |
+| Hex Diff | Package diff viewer | diff.hex.pm | diff.staging.hex.pm | [hexpm/diff](https://github.com/hexpm/diff) |
+
+> **Out of scope:** billing.hex.pm is excluded from this security documentation.
+
+### Client Libraries
+
+| Name | Description | Repository |
+|------|-------------|------------|
+| Hex | Elixir Hex client | [hexpm/hex](https://github.com/hexpm/hex) |
+| Hex Core | Core library for Elixir/Erlang clients | [hexpm/hex_core](https://github.com/hexpm/hex_core) |
+| Hex Solver | Version constraint resolver | [hexpm/hex_solver](https://github.com/hexpm/hex_solver) |
+| hexpm-rust | Rust Hex client (used by Gleam) | [gleam-lang/hexpm-rust](https://github.com/gleam-lang/hexpm-rust) |
+
+### Build Tools
+
+| Name | Description | Repository |
+|------|-------------|------------|
+| Mix | Elixir build tool | [elixir-lang/elixir](https://github.com/elixir-lang/elixir) (lib/mix) |
+| Rebar3 | Erlang build tool | [erlang/rebar3](https://github.com/erlang/rebar3) |
+| erlang.mk | Erlang build tool | [ninenines/erlang.mk](https://github.com/ninenines/erlang.mk) |
+| Gleam | Gleam language & build tool | [gleam-lang/gleam](https://github.com/gleam-lang/gleam) |
+
+## System Context
+
+Shows the Hex ecosystem and its relationships with users and external systems.
+
+```mermaid
+C4Context
+ title System Context Diagram for Hex Package Manager
+
+ Person(consumer, "Package Consumer", "Developers and CI/CD systems using mix, rebar3, or gleam")
+ Person(maintainer, "Package Maintainer", "Publishes and manages packages")
+ Person(operator, "Hex.pm Operator", "Maintains registry infrastructure")
+
+ System(hex, "Hex.pm", "Package registry API and web UI")
+ System_Ext(fastly, "Fastly CDN", "Global content delivery and edge compute")
+ System_Ext(storage, "Cloud Storage", "Package artifacts and registry files")
+
+ System_Ext(github, "GitHub", "OAuth authentication and source code hosting")
+ System_Ext(email, "Email Service", "Sends notifications and password resets")
+
+ Rel(consumer, hex, "API requests", "HTTPS")
+ Rel(consumer, fastly, "Repository requests", "HTTPS")
+ Rel(maintainer, hex, "Publishes packages", "HTTPS + API Key")
+ Rel(operator, hex, "Administers", "Internal")
+
+ Rel(fastly, storage, "Serves registry + tarballs", "HTTPS cached")
+
+ Rel(hex, github, "OAuth authentication")
+ Rel(hex, email, "Sends notifications")
+ Rel(hex, storage, "Stores packages")
+
+ UpdateLayoutConfig($c4ShapeInRow="3", $c4BoundaryInRow="1")
+```
+
+**Actors** (see [Actors](actors.md) for details):
+- **Package Consumers** - Developers and CI/CD systems that fetch packages
+- **Package Maintainers** - Publish and manage packages via the web UI or CLI
+- **Organization Administrators** - Manage private repositories and teams
+- **Hex.pm Operators** - Maintain and operate the registry infrastructure
+
+**External Systems:**
+- **GitHub** provides OAuth authentication and hosts package source code
+- **Email Service** sends password resets, ownership notifications, etc.
+- **Fastly CDN** caches and delivers registry files and package tarballs globally
+
+## Container Diagram
+
+Shows the internal services and data stores within the Hex ecosystem.
+
+```mermaid
+C4Container
+ title Container Diagram for Hex Package Manager
+
+ Person(consumer, "Package Consumer", "Uses mix, rebar3, or gleam")
+ Person(maintainer, "Package Maintainer", "Publishes packages")
+
+ System_Boundary(hex, "Hex Ecosystem") {
+ Container(fastly, "Fastly CDN", "Compute@Edge", "Caches content, routes requests, runs edge logic")
+
+ Container(hexpm_web, "hex.pm", "Phoenix/Elixir", "Web UI, HTTP API, package management")
+ Container(hexdocs, "hexdocs.pm", "Phoenix/Elixir", "Documentation hosting and search")
+ Container(preview, "preview.hex.pm", "Phoenix/Elixir", "Package preview before publishing")
+ Container(diff, "diff.hex.pm", "Phoenix/Elixir", "Visual diff between package versions")
+
+ ContainerDb(postgres, "PostgreSQL", "Database", "Users, packages, releases, API keys, organizations")
+ ContainerDb(aws_s3, "Registry Storage", "AWS S3", "Tarballs and registry files")
+ ContainerDb(gcs, "Service Storage", "Google Cloud Storage", "Documentation, diff cache, preview cache")
+ Container(sqs_preview, "Preview Event Queue", "AWS SQS", "S3 ObjectCreated/Removed notifications consumed by preview")
+ Container(sqs_docs, "Docs Event Queue", "AWS SQS", "S3 ObjectCreated/Removed notifications consumed by hexdocs")
+
+ Container(registry_worker, "Registry Builder", "Elixir Worker", "Rebuilds registry after publishes")
+ Container(notification_worker, "Notification Worker", "Elixir Worker", "Sends emails and webhooks")
+ }
+
+ System_Ext(email, "Email Service", "Sends notifications")
+
+ Rel(consumer, fastly, "Fetches packages", "HTTPS")
+ Rel(maintainer, fastly, "Publishes packages", "HTTPS")
+
+ Rel(fastly, aws_s3, "Registry files", "/names, /versions, /packages/*")
+ Rel(fastly, aws_s3, "Tarballs", "/tarballs/*")
+ Rel(fastly, hexpm_web, "API requests", "/api/*")
+ Rel(fastly, gcs, "Documentation, preview", "HTTPS")
+
+ Rel(hexpm_web, postgres, "Reads/writes", "PostgreSQL")
+ Rel(hexpm_web, aws_s3, "Stores packages", "S3 API")
+ Rel(hexpm_web, registry_worker, "Triggers rebuild")
+ Rel(hexpm_web, notification_worker, "Queues notifications")
+
+ Rel(aws_s3, sqs_preview, "ObjectCreated/Removed events")
+ Rel(aws_s3, sqs_docs, "ObjectCreated/Removed events")
+ Rel(hexdocs, sqs_docs, "Consumes tarball/docs events", "SQS")
+ Rel(hexdocs, aws_s3, "Reads tarballs", "S3 API")
+ Rel(hexdocs, gcs, "Writes rendered docs", "GCS API")
+ Rel(preview, sqs_preview, "Consumes tarball events", "SQS")
+ Rel(preview, aws_s3, "Reads tarballs", "S3 API")
+ Rel(preview, gcs, "Writes extracted previews", "GCS API")
+ Rel(diff, fastly, "Fetches tarballs", "repo.hex.pm")
+ Rel(diff, gcs, "Caches diffs", "GCS API")
+
+ Rel(registry_worker, aws_s3, "Writes registry", "S3 API")
+ Rel(notification_worker, email, "Sends email", "SendGrid HTTP API")
+
+ UpdateLayoutConfig($c4ShapeInRow="4", $c4BoundaryInRow="1")
+```
+
+## Deployment Diagram
+
+Shows the production infrastructure deployment topology.
+
+```mermaid
+C4Deployment
+ title Deployment Diagram for Hex Package Manager
+
+ Deployment_Node(internet, "Internet", "") {
+ Deployment_Node(client_node, "Client Machine", "") {
+ Container(client, "Build Tool", "mix/rebar3/gleam", "Fetches packages and registry")
+ }
+ Deployment_Node(browser_node, "Browser", "") {
+ Container(browser, "Web Browser", "", "Access web UI")
+ }
+ }
+
+ Deployment_Node(fastly_edge, "Fastly Edge", "Global POPs") {
+ Container(edge, "Edge Cache + Compute@Edge", "Fastly", "Caches registry and tarballs, routes requests")
+ }
+
+ Deployment_Node(production, "Production Environment", "") {
+ Deployment_Node(web_tier, "Web Tier", "") {
+ Container(hex_prod, "hex.pm", "Phoenix/Elixir", "Main application")
+ Container(hexdocs_prod, "hexdocs.pm", "Phoenix/Elixir", "Documentation")
+ Container(preview_prod, "preview.hex.pm", "Phoenix/Elixir", "Preview")
+ Container(diff_prod, "diff.hex.pm", "Phoenix/Elixir", "Diff viewer")
+ }
+ Deployment_Node(data_tier, "Data Tier", "") {
+ ContainerDb(pg_prod, "PostgreSQL", "Cloud SQL", "Application data")
+ ContainerDb(s3_prod, "Registry Bucket", "AWS S3", "Tarballs and registry files")
+ ContainerDb(gcs_prod, "Service Buckets", "Google Cloud Storage", "Docs, diff cache, preview cache")
+ Container(sqs_preview_prod, "Preview Event Queue", "AWS SQS", "Tarball events for preview")
+ Container(sqs_docs_prod, "Docs Event Queue", "AWS SQS", "Tarball/docs events for hexdocs")
+ }
+ }
+
+ Deployment_Node(mirrors, "Mirror Infrastructure", "") {
+ Container(trusted_mirror, "Trusted Mirror", "Org-controlled", "Full authentication support")
+ Container(untrusted_mirror, "Untrusted Mirror", "Community", "Public packages only - NO credentials")
+ }
+
+ Rel(client, edge, "HTTPS")
+ Rel(browser, edge, "HTTPS")
+
+ Rel(edge, hex_prod, "Cache MISS", "/api/*")
+ Rel(edge, s3_prod, "Cache MISS", "Registry + tarballs")
+
+ Rel(hex_prod, pg_prod, "PostgreSQL")
+ Rel(hex_prod, s3_prod, "S3 API")
+
+ Rel(s3_prod, sqs_preview_prod, "ObjectCreated/Removed events")
+ Rel(s3_prod, sqs_docs_prod, "ObjectCreated/Removed events")
+ Rel(hexdocs_prod, sqs_docs_prod, "Consumes events", "SQS")
+ Rel(hexdocs_prod, s3_prod, "Reads tarballs", "S3 API")
+ Rel(hexdocs_prod, gcs_prod, "Writes rendered docs", "GCS API")
+ Rel(diff_prod, edge, "Fetch tarballs", "repo.hex.pm")
+ Rel(diff_prod, gcs_prod, "Diff cache", "GCS API")
+ Rel(preview_prod, sqs_preview_prod, "Consumes events", "SQS")
+ Rel(preview_prod, s3_prod, "Reads tarballs", "S3 API")
+ Rel(preview_prod, gcs_prod, "Writes previews", "GCS API")
+
+ Rel(client, trusted_mirror, "Alternative path", "With auth")
+ Rel(client, untrusted_mirror, "Alternative path", "NO auth - public only")
+
+ Rel(trusted_mirror, edge, "Proxies via CDN")
+ Rel(untrusted_mirror, edge, "Public packages only")
+```
+
+### Deployment Security Notes
+
+- **CDN Strategy**: All traffic flows through Fastly; registry files and tarballs are heavily cached
+- **Mirror Trust**: Trusted mirrors can proxy authenticated requests; untrusted mirrors only serve public packages
+- **High Availability**: S3 provides artifact durability; Fastly provides global redundancy
+
+## Key Components
+
+| Component | Description | Security Role |
+|-----------|-------------|---------------|
+| hex.pm API | Package registry API | Authentication, authorization, publishing |
+| hex.pm Web | Web interface | User management, 2FA, session handling |
+| Fastly CDN + AWS S3 | Content delivery and registry/tarball storage | Artifact integrity, signed registry |
+| Google Cloud Storage | Documentation, diff cache, preview cache | Content isolation |
+| hexdocs.pm | Documentation hosting | Content isolation, XSS prevention |
+| Hex clients | Build tool integrations (mix, rebar3, gleam) | Signature verification, checksum validation |
+| Registry Builder | Background worker | Signs registry files after publish |
+| Notification Worker | Background worker | Sends security-relevant notifications |
+
+## Trust Boundaries
+
+```mermaid
+C4Context
+ title Trust Boundary Diagram for Hex Package Manager
+
+ Boundary(trusted, "Trusted Zone") {
+ System(hexpm, "hex.pm", "Main application")
+ System(fastly, "Fastly CDN", "Edge delivery")
+ SystemDb(s3, "AWS S3", "Registry + tarballs")
+ SystemDb(gcs, "Google Cloud Storage", "Docs, diff cache, preview cache")
+ SystemDb(pg, "PostgreSQL", "Application data")
+ }
+
+ Boundary(semi_trusted, "Semi-Trusted Zone") {
+ System(trusted_mirror, "Trusted Mirrors", "Organization-controlled mirrors")
+ }
+
+ Boundary(untrusted, "Untrusted Zone") {
+ Person(client, "Client", "Build tools: mix, rebar3, gleam")
+ System(untrusted_mirror, "Untrusted Mirrors", "Community mirrors")
+ }
+
+ Rel(client, hexpm, "API requests", "HTTPS + API Key")
+ Rel(client, fastly, "Repository requests", "HTTPS + API Key")
+ Rel(client, trusted_mirror, "Credentials OK", "HTTPS + API Key")
+ Rel(client, untrusted_mirror, "NO CREDENTIALS", "HTTPS only")
+
+ Rel(fastly, hexpm, "Internal")
+ Rel(trusted_mirror, fastly, "Proxies requests")
+ Rel(untrusted_mirror, fastly, "Public packages only")
+
+ UpdateLayoutConfig($c4ShapeInRow="4", $c4BoundaryInRow="3")
+```
+
+### Boundary 1: Client to Registry API
+
+- **Crosses**: User credentials, API tokens, OAuth tokens
+- **Controls**: TLS, token scoping, 2FA for write operations
+
+### Boundary 2: Client to Repository (CDN)
+
+- **Crosses**: Package artifacts, registry data, API tokens, OAuth tokens (private packages)
+- **Controls**: Signed registry, checksums, signature verification
+- **Critical**: Clients must NEVER send credentials to untrusted mirrors
+
+### Boundary 3: Internal Services
+
+- **Crosses**: Database connections, internal APIs
+- **Controls**: Network isolation, access control
+
+### Boundary 4: Browser to Documentation
+
+- **Crosses**: User-generated documentation content
+- **Controls**: Separate origin, CSP headers
+
+## Communication Protocols
+
+| Path | Protocol | Format | Authentication | Integrity |
+|------|----------|--------|----------------|-----------|
+| Client → Registry files | HTTPS | Protobuf + gzip | None (public) or API key (private) or OAuth2 (private) | RSA-PKCS1-SHA512 signatures |
+| Client → Tarballs | HTTPS | tar | None (public) or API key (private) or OAuth2 (private) | Checksums |
+| Client → API | HTTPS | JSON | API key (Bearer token) or OAuth | TLS |
+| Browser → Web | HTTPS | HTML | Session cookie | TLS |
+| Browser → Docs | HTTPS | HTML | None | TLS + CSP |
+| hex.pm → PostgreSQL | TCP | PostgreSQL protocol | Connection credentials | - |
+| hex.pm → S3 | HTTPS | S3 API | IAM credentials | TLS |
+
+## Data Flow Diagrams
+
+### Publishing Flow
+
+```mermaid
+sequenceDiagram
+ participant Client as Client (mix/rebar3/gleam)
+ participant API as hex.pm API
+ participant DB as PostgreSQL
+ participant S3 as S3 Storage
+ participant Worker as Registry Builder
+ participant CDN as Fastly CDN
+
+ Client->>API: Publish package (Bearer: API key or OAuth access token; OAuth tokens additionally require x-hex-otp)
+ API->>API: Validate authentication & authorization
+ API->>DB: Store package metadata
+ API->>S3: Upload tarball
+ API->>Worker: Trigger registry rebuild
+ Worker->>DB: Read package data
+ Worker->>Worker: Build & sign registry files
+ Worker->>S3: Upload signed registry
+ API->>CDN: Cache invalidation
+ API-->>Client: Success response
+```
+
+### Installation Flow
+
+```mermaid
+sequenceDiagram
+ participant Client as Client (mix/rebar3/gleam)
+ participant CDN as Fastly CDN
+ participant S3 as S3 Storage
+
+ Client->>CDN: Fetch registry (/names, /versions)
+ CDN->>S3: Cache miss (if needed)
+ S3-->>CDN: Registry files
+ CDN-->>Client: Signed registry
+ Client->>Client: Verify RSA-PKCS1-SHA512 signature
+ Client->>CDN: Fetch package tarball
+ CDN->>S3: Cache miss (if needed)
+ S3-->>CDN: Tarball
+ CDN-->>Client: Package tarball
+ Client->>Client: Verify checksum
+ Client->>Client: Extract contents
+```
diff --git a/security/threat-model/assets.md b/security/threat-model/assets.md
new file mode 100644
index 0000000..334c1d8
--- /dev/null
+++ b/security/threat-model/assets.md
@@ -0,0 +1,142 @@
+# Assets
+
+This document identifies the assets protected by the Hex ecosystem.
+
+For where these assets are stored and how they flow through the system, see [Architecture](architecture.md). For threats targeting these assets, see [Threats](threats.md).
+
+## Critical Assets
+
+### Package Artifacts
+
+Package tarballs containing source code distributed to consumers.
+
+| Attribute | Description |
+|-----------|-------------|
+| Location | S3 storage, served via CDN |
+| Impact if compromised | Arbitrary code execution in downstream systems |
+| Protection | Checksums, signed registry, immutable versions (after one hour, or 24 hours for newly created packages) |
+
+### Registry Metadata
+
+Signed protobuf files containing package versions, dependencies, and checksums.
+
+| Attribute | Description |
+|-----------|-------------|
+| Location | S3 storage (protobuf files), served via CDN |
+| Impact if compromised | Dependency confusion, version manipulation |
+| Protection | RSA-PKCS1-SHA512 signatures, repository field verification |
+
+### Registry Signing Key
+
+Private RSA key used to sign all registry files.
+
+| Attribute | Description |
+|-----------|-------------|
+| Location | Secrets management |
+| Impact if compromised | Attacker could sign malicious registry, bypassing all client verification |
+| Protection | Access control, rotation procedures |
+
+### Maintainer Accounts
+
+User credentials and authentication state.
+
+| Attribute | Description |
+|-----------|-------------|
+| Location | Database (hashed passwords, TOTP secrets) |
+| Impact if compromised | Unauthorized package publishing |
+| Protection | Strong passwords, 2FA, OAuth tokens |
+
+### API Tokens
+
+Bearer tokens for API access.
+
+| Attribute | Description |
+|-----------|-------------|
+| Location | Database (hashed), client machines (plaintext/encrypted) |
+| Impact if compromised | Unauthorized actions within token scope |
+| Protection | Scoping, revocation, short-lived OAuth tokens |
+
+## High Value Assets
+
+### Documentation Content
+
+User-generated HTML documentation.
+
+| Attribute | Description |
+|-----------|-------------|
+| Location | S3 storage, served via hexdocs.pm |
+| Impact if compromised | XSS attacks, phishing |
+| Protection | CSP headers, separate origin (planned) |
+
+### Package Ownership
+
+Namespace mappings and collaborator permissions.
+
+| Attribute | Description |
+|-----------|-------------|
+| Location | Database |
+| Impact if compromised | Package takeover, typosquatting enablement |
+| Protection | Ownership model, audit logs |
+
+### Organization Data
+
+Private repositories and billing information.
+
+| Attribute | Description |
+|-----------|-------------|
+| Location | Database |
+| Impact if compromised | Data breach, unauthorized access |
+| Protection | Access control, authentication requirements |
+
+## Supporting Assets
+
+### Audit Logs
+
+Records of security-relevant actions.
+
+| Attribute | Description |
+|-----------|-------------|
+| Location | Database, log aggregation |
+| Impact if compromised | Loss of forensic capability |
+| Protection | Append-only, retention policies |
+
+### Build Metadata
+
+SBOM and provenance information.
+
+| Attribute | Description |
+|-----------|-------------|
+| Location | Package metadata, external attestations |
+| Impact if compromised | False provenance claims |
+| Protection | Signed attestations (future) |
+
+### Infrastructure Credentials
+
+Service accounts and deployment keys.
+
+| Attribute | Description |
+|-----------|-------------|
+| Location | Secrets management |
+| Impact if compromised | Full system compromise |
+| Protection | Rotation, least privilege, monitoring |
+
+## Asset Classification Matrix
+
+Impact ratings use [CVSS v4.0](https://www.first.org/cvss/v4.0/specification-document) semantics:
+- **None** - No impact
+- **Low** - Limited impact
+- **High** - Serious impact
+
+| Asset | Confidentiality | Integrity | Availability |
+|-------|-----------------|-----------|--------------|
+| Package Artifacts | None | High | High |
+| Registry Metadata | None | High | High |
+| Registry Signing Key | High | High | High |
+| Maintainer Accounts | High | High | Low |
+| API Tokens | High | High | Low |
+| Documentation Content | None | Low | Low |
+| Package Ownership | Low | High | Low |
+| Organization Data | High | High | Low |
+| Audit Logs | Low | High | Low |
+| Build Metadata | None | High | None |
+| Infrastructure Credentials | High | High | High |
diff --git a/security/threat-model/assumptions.md b/security/threat-model/assumptions.md
new file mode 100644
index 0000000..705989d
--- /dev/null
+++ b/security/threat-model/assumptions.md
@@ -0,0 +1,114 @@
+# Assumptions
+
+This document describes the security assumptions and boundaries of the Hex ecosystem.
+
+For controls that address threats under these assumptions, see [Mitigations](mitigations.md).
+
+## What We Assume
+
+### About Maintainers
+
+| Assumption | Implication |
+|------------|-------------|
+| Development environments may be compromised | Build provenance cannot be guaranteed without attestations |
+| Maintainers are responsible for their package security | Registry does not audit package contents |
+| Maintainers may make mistakes | Leaked credential detection, but cannot prevent all exposures |
+
+### About Users
+
+| Assumption | Implication |
+|------------|-------------|
+| Users execute packages in trusted environments | Registry cannot protect against local exploits |
+| Users are responsible for evaluating trustworthiness | Download counts and metadata provided, but no endorsement |
+| Users have secure credential storage | Tokens stored locally; compromise is user's responsibility |
+
+### About Infrastructure
+
+| Assumption | Implication |
+|------------|-------------|
+| Cloud providers (Google Cloud, AWS, Fastly) operate securely | Infrastructure compromise outside our control |
+| TLS provides confidentiality and integrity in transit | No additional transport encryption |
+| Cryptographic primitives (RSA, SHA-256, SHA-512) are secure | RSA-PKCS1-SHA512 signatures and SHA-256 checksums depend on this |
+
+### About Clients
+
+| Assumption | Implication |
+|------------|-------------|
+| Official clients implement verification correctly | Security depends on client-side checks |
+| Users use current client versions | Old clients may have vulnerabilities |
+| Clients run in trusted local environments | Local cache tampering outside our control |
+
+## What We Do NOT Guarantee
+
+### Package Content
+
+| Non-Guarantee | Reason |
+|---------------|--------|
+| Packages are safe to use | We do not audit source code |
+| Packages do what they claim | No functional verification |
+| No malicious packages exist | Detection is imperfect; controls reduce but don't eliminate risk |
+
+### Maintainer Identity
+
+| Non-Guarantee | Reason |
+|---------------|--------|
+| Real-world identity of maintainers | Account verification is email-based only |
+| Organization membership implies employment | No employment verification |
+
+### Availability
+
+| Non-Guarantee | Reason |
+|---------------|--------|
+| 100% uptime | Maintenance windows and incidents may occur |
+| Protection against all DDoS | Attacks may cause temporary unavailability |
+
+### Historical Packages
+
+| Non-Guarantee | Reason |
+|---------------|--------|
+| All historical versions are safe | Vulnerabilities may exist in old versions |
+| Retired packages are removed | Kept available for reproducibility |
+
+## Security Boundaries
+
+### Registry Responsibility
+
+**We are responsible for:**
+- Protecting registry infrastructure
+- Ensuring integrity of distributed artifacts
+- Authenticating publishing operations
+- Providing audit capabilities
+
+**We are NOT responsible for:**
+- Security of maintainer environments
+- Security of package contents
+- Security of user environments
+- Vulnerabilities in packages
+
+### Trust Model
+
+> [!TIP]
+> **What users CAN trust:**
+> - Artifact matches what maintainer published (integrity)
+> - Registry metadata is authentic (signatures)
+> - Publishing required authentication
+
+> [!CAUTION]
+> **What users CANNOT assume:**
+> - Package is safe to execute
+> - Maintainer is trustworthy
+> - Package has no vulnerabilities
+> - Dependencies are safe
+
+## Future Improvements
+
+Planned features that will change (but not eliminate) these assumptions:
+
+| Feature | Impact on Assumptions |
+|---------|----------------------|
+| Trusted Publishing (OIDC) | Provides build provenance; reduces "maintainer environment" assumption |
+| Malware scanning | Provides some content assurance; still cannot guarantee safety |
+| Signed attestations | Provides verifiable claims about build process |
+| WebAuthn/Passkeys | Reduces account compromise risk |
+
+See [Mitigations](mitigations.md) for current status of these features.
diff --git a/security/threat-model/client-flows.md b/security/threat-model/client-flows.md
new file mode 100644
index 0000000..92db614
--- /dev/null
+++ b/security/threat-model/client-flows.md
@@ -0,0 +1,715 @@
+# Client Flows
+
+This document describes how package manager clients interact with the Hex ecosystem, including API calls, caching behavior, and verification flows.
+
+## Client Architecture Overview
+
+```mermaid
+C4Context
+ title Client Library Architecture
+
+ Person(dev, "Developer", "Runs build commands")
+
+ Boundary(elixir_erlang, "Elixir/Erlang Clients") {
+ System(mix, "Mix", "Elixir build tool")
+ System(rebar3, "Rebar3", "Erlang build tool")
+ System(hex_client, "Hex Client", "hexpm/hex - Mix integration")
+ System(hex_core, "Hex Core", "hexpm/hex_core - Core library")
+ System(hex_solver, "Hex Solver", "hexpm/hex_solver - Version resolver")
+ }
+
+ Boundary(gleam_client, "Gleam Client") {
+ System(gleam, "Gleam", "Gleam build tool")
+ System(hexpm_rust, "hexpm-rust", "gleam-lang/hexpm-rust - Rust Hex client")
+ }
+
+ System_Ext(hexpm, "hex.pm", "Package registry")
+
+ Rel(dev, mix, "mix deps.get")
+ Rel(dev, rebar3, "rebar3 compile")
+ Rel(dev, gleam, "gleam build")
+
+ Rel(mix, hex_client, "Uses")
+ Rel(hex_client, hex_core, "Uses")
+ Rel(hex_client, hex_solver, "Uses")
+ Rel(rebar3, hex_core, "Uses directly")
+
+ Rel(gleam, hexpm_rust, "Uses")
+
+ Rel(hex_core, hexpm, "HTTPS", "Registry + tarballs")
+ Rel(hexpm_rust, hexpm, "HTTPS", "Registry + tarballs")
+
+ UpdateLayoutConfig($c4ShapeInRow="3", $c4BoundaryInRow="2")
+```
+
+---
+
+## 1. Mix (Elixir) Dependency Installation
+
+Command: `mix deps.get`
+
+### Authentication
+
+Mix/Hex uses OAuth2 Device Authorization Grant ([RFC 8628](https://datatracker.ietf.org/doc/html/rfc8628)) for interactive authentication. `mix hex.user auth` requests the `api repositories` scopes, which include both read and write permissions; write operations additionally require 2FA to be enabled on the account and an OTP code in the `x-hex-otp` header. API keys can still be used directly, especially for CI environments; API keys cannot use 2FA. See [OAuth2 Device Authorization Grant](#6-oauth2-device-authorization-grant) for details.
+
+### Cache Locations
+
+| Cache | Path | Contents |
+|-------|------|----------|
+| Registry | `~/.hex/cache.ets` | ETS file with package versions, deps, checksums |
+| Packages | `~/.hex/packages/hexpm/{package}-{version}.tar` | Downloaded tarballs |
+| Config | `~/.hex/hex.config` | OAuth tokens, API keys |
+| ETags | Inside `cache.ets` | `{:registry_etag, repo, package}` |
+
+Environment variable `HEX_HOME` overrides the default `~/.hex` location.
+
+### Sequence Diagram
+
+```mermaid
+sequenceDiagram
+ autonumber
+ participant Dev as Developer
+ participant Mix as Mix
+ participant Hex as Hex Client
+ participant HexCore as Hex Core
+ participant Solver as Hex Solver
+ participant Cache as Local Cache
~/.hex/
+ participant CDN as Fastly CDN
+ participant S3 as S3 Storage
+ participant API as hex.pm API
+
+ Dev->>Mix: mix deps.get
+ Mix->>Hex: converge(deps, lock)
+
+ Note over Hex,Cache: Registry Initialization
+ Hex->>Cache: Open cache.ets
+ Cache-->>Hex: ETS table reference
+
+ Note over Hex,API: Authentication Check (for authenticated operations)
+ Hex->>Cache: Read hex.config
+ alt Has OAuth Token
+ Hex->>Hex: Check token expiry (expires within 5 min?)
+ opt Token Expired or Expiring Soon
+ Hex->>API: POST /api/oauth/token
grant_type=refresh_token
+ API-->>Hex: New access_token + refresh_token
+ Hex->>Cache: Update hex.config
+ end
+ else Has API Key
+ Note over Hex: Use API key directly
+ end
+
+ Note over Hex,S3: Registry Prefetch
+ Hex->>HexCore: get_package(repo, name, etag)
+
+ loop For each dependency
+ HexCore->>Cache: Get cached ETag
+ Cache-->>HexCore: ETag or nil
+
+ HexCore->>CDN: GET /packages/{name}
If-None-Match: {etag}
+
+ alt Cache Hit (304 Not Modified)
+ CDN-->>HexCore: 304 Not Modified
+ HexCore->>Cache: Use cached data
+ else Cache Miss (200 OK)
+ CDN->>S3: Fetch from origin
+ S3-->>CDN: Signed protobuf (gzip)
+ CDN-->>HexCore: 200 OK + ETag
+
+ Note over HexCore: Verify RSA-PKCS1-SHA512 signature
+ HexCore->>HexCore: gunzip → decode Signed protobuf
+ HexCore->>HexCore: verify(payload, signature, public_key)
+
+ alt Signature Invalid
+ HexCore-->>Hex: {error, bad_signature}
+ Hex-->>Mix: Abort with security error
+ end
+
+ HexCore->>Cache: Store package data + ETag
+ end
+ end
+
+ Note over Hex,Solver: Dependency Resolution
+ Hex->>Solver: resolve(requirements)
+ Solver->>Cache: Read versions, deps from cache
+ Solver->>Solver: Find optimal version set
+ Solver-->>Hex: Resolved versions
+
+ Note over Hex,S3: Package Download
+ loop For each resolved package
+ Hex->>Cache: Check ~/.hex/packages/{repo}/{name}-{version}.tar
+ alt Cached & checksum matches
+ Cache-->>Hex: Use cached tarball
+ else Not cached or checksum mismatch
+ Hex->>HexCore: get_tarball(repo, name, version)
+ HexCore->>CDN: GET /tarballs/{name}-{version}.tar
+ CDN->>S3: Fetch tarball
+ S3-->>CDN: Package tarball
+ CDN-->>HexCore: Tarball bytes
+
+ Note over HexCore: Verify outer checksum (SHA-256)
+ HexCore->>HexCore: SHA256(tarball) == registry.outer_checksum?
+
+ alt Checksum Mismatch
+ HexCore-->>Hex: {error, checksum_mismatch}
+ Hex-->>Mix: Abort - possible tampering
+ end
+
+ HexCore-->>Hex: Tarball bytes
+ Hex->>Cache: Save to packages/{repo}/
+ end
+
+ Hex->>Hex: Extract tarball to deps/{app}/
+ end
+
+ Hex->>Mix: Updated lock
+ Mix->>Mix: Write mix.lock
+ Mix-->>Dev: Dependencies fetched
+```
+
+### Error Handling
+
+```mermaid
+sequenceDiagram
+ participant Hex as Hex Client
+ participant Cache as Local Cache
+ participant CDN as Fastly CDN
+
+ Note over Hex,CDN: Registry Update Failure
+ Hex->>CDN: GET /packages/{name}
+ CDN-->>Hex: Network error / timeout
+
+ Hex->>Cache: Check for cached registry
+ alt Cache exists
+ Cache-->>Hex: Cached registry data
+ Hex->>Hex: ⚠️ Warn user: using cached registry
+ Note over Hex: Continue with cached data
+ else No cache
+ Hex-->>Hex: ❌ Abort: cannot resolve dependencies
+ end
+```
+
+---
+
+## 2. Rebar3 (Erlang) Dependency Installation
+
+Command: `rebar3 compile` (with hex plugin)
+
+### Authentication
+
+Rebar3 uses basic authentication to generate API keys. Unlike Mix/Hex and Gleam, it does not support OAuth2 Device Authorization Grant.
+
+### Cache Locations
+
+| Cache | Path | Contents |
+|-------|------|----------|
+| Registry index | `~/.cache/rebar3/hex/packages.idx` | ETS index of hex package metadata |
+| Packages | `~/.cache/rebar3/hex/hexpm/packages/` | Downloaded tarballs |
+| Config | `~/.config/rebar3/hex.config` | API keys |
+| Lock | `rebar.lock` | Resolved versions with checksums |
+
+### Sequence Diagram
+
+```mermaid
+sequenceDiagram
+ autonumber
+ participant Dev as Developer
+ participant Rebar as Rebar3
+ participant HexCore as Hex Core
(hex_core)
+ participant Cache as Local Cache
~/.cache/rebar3/hex/
+ participant CDN as Fastly CDN
+ participant S3 as S3 Storage
+
+ Dev->>Rebar: rebar3 compile
+ Rebar->>Rebar: Parse rebar.config
+
+ Note over Rebar,S3: Registry Fetch
+ Rebar->>HexCore: hex_repo:get_versions(Config)
+ HexCore->>CDN: GET /versions
+ CDN->>S3: Fetch (if not cached)
+ S3-->>CDN: Signed protobuf (gzip)
+ CDN-->>HexCore: Versions data
+
+ Note over HexCore: Verify signature
+ HexCore->>HexCore: gunzip → verify RSA-PKCS1-SHA512
+ HexCore-->>Rebar: Package versions list
+
+ loop For each dependency
+ Rebar->>HexCore: hex_repo:get_package(Config, Name)
+ HexCore->>Cache: Check ETag
+ HexCore->>CDN: GET /packages/{name}
If-None-Match: {etag}
+
+ alt 304 Not Modified
+ CDN-->>HexCore: Use cache
+ else 200 OK
+ CDN-->>HexCore: Package metadata
+ HexCore->>HexCore: Verify signature
+ HexCore->>Cache: Store + ETag
+ end
+ HexCore-->>Rebar: Package releases & deps
+ end
+
+ Note over Rebar: Dependency Resolution
+ Rebar->>Rebar: Resolve version constraints
+
+ Note over Rebar,S3: Download Packages
+ loop For each resolved package
+ Rebar->>Cache: Check packages/{name}-{version}.tar
+ alt Not cached
+ Rebar->>HexCore: hex_repo:get_tarball(Config, Name, Version)
+ HexCore->>CDN: GET /tarballs/{name}-{version}.tar
+ CDN->>S3: Fetch tarball
+ S3-->>CDN: Package tarball
+ CDN-->>HexCore: Tarball
+
+ Note over HexCore: Verify SHA-256 checksum
+ HexCore->>HexCore: Unpack & verify checksums
+ HexCore-->>Rebar: Package contents
+
+ Rebar->>Cache: Cache tarball
+ end
+ Rebar->>Rebar: Extract to _build/
+ end
+
+ Rebar->>Rebar: Write rebar.lock
+ Rebar->>Rebar: Compile dependencies
+ Rebar-->>Dev: Build complete
+```
+
+---
+
+## 3. Gleam Dependency Installation
+
+Command: `gleam build`
+
+### Authentication
+
+Gleam uses OAuth2 Device Authorization Grant ([RFC 8628](https://datatracker.ietf.org/doc/html/rfc8628)) for interactive authentication, triggered automatically when an authenticated operation is needed. The Gleam Hex client requests the `api:write` scope (read and write access to the API, no per-repository scope); write operations additionally require 2FA to be enabled on the account and an OTP code in the `x-hex-otp` header. API keys can be used via the `HEXPM_API_KEY` environment variable for CI environments; API keys cannot use 2FA. See [OAuth2 Device Authorization Grant](#6-oauth2-device-authorization-grant) for details.
+
+### Cache Locations
+
+| Cache | Path | Contents |
+|-------|------|----------|
+| Packages | `~/.cache/gleam/hex/hexpm/packages/` | Downloaded tarballs |
+| Credentials | `~/.cache/gleam/hex/hexpm/credentials.toml` | OAuth refresh token (encrypted with a user-supplied local password); legacy API-key file `credentials` is migrated and deleted |
+| Build | `./build/` | Compiled packages |
+| Manifest | `manifest.toml` | Resolved versions with checksums |
+
+### Sequence Diagram
+
+```mermaid
+sequenceDiagram
+ autonumber
+ participant Dev as Developer
+ participant Gleam as Gleam
+ participant HexRust as hexpm-rust
+ participant CDN as Fastly CDN
+ participant S3 as S3 Storage
+
+ Dev->>Gleam: gleam build
+ Gleam->>Gleam: Parse gleam.toml
+
+ Note over Gleam,S3: Fetch Version Index
+ Gleam->>HexRust: get_versions_request()
+ HexRust->>CDN: GET /versions
+ CDN->>S3: Fetch (if not cached)
+ S3-->>CDN: Signed protobuf (gzip)
+ CDN-->>HexRust: Compressed response
+
+ Note over HexRust: Verify signature (ring crate)
+ HexRust->>HexRust: gunzip → decode Signed protobuf
+ HexRust->>HexRust: RSA-PKCS1-SHA512 verify
+ HexRust-->>Gleam: All package versions
+
+ loop For each dependency
+ Gleam->>HexRust: get_package_request(name)
+ HexRust->>CDN: GET /packages/{name}
+ CDN-->>HexRust: Package metadata (signed)
+
+ HexRust->>HexRust: Verify signature
+ HexRust-->>Gleam: Releases & dependencies
+ end
+
+ Note over Gleam: Version Resolution
+ Gleam->>Gleam: Resolve constraints (PubGrub algorithm)
+
+ Note over Gleam,S3: Download Packages
+ loop For each resolved package
+ Gleam->>HexRust: get_tarball_request(name, version)
+ HexRust->>CDN: GET /tarballs/{name}-{version}.tar
+ CDN->>S3: Fetch tarball
+ S3-->>CDN: Package tarball
+ CDN-->>HexRust: Tarball bytes
+
+ Note over HexRust: Verify SHA-256 checksum
+ HexRust->>HexRust: SHA256(tarball) == expected?
+
+ alt Checksum Mismatch
+ HexRust-->>Gleam: IncorrectChecksum error
+ Gleam-->>Dev: ❌ Abort - integrity failure
+ end
+
+ HexRust-->>Gleam: Verified tarball
+ Gleam->>Gleam: Extract to build/packages/
+ end
+
+ Gleam->>Gleam: Write manifest.toml
+ Gleam->>Gleam: Compile Gleam + Erlang
+ Gleam-->>Dev: Build complete
+```
+
+---
+
+## 4. Package Publishing
+
+Command: `mix hex.publish`, `rebar3 hex publish`, or `gleam publish`
+
+### Authentication for Publishing
+
+Publishing requires write permissions:
+
+| Client | Authentication Method | 2FA Requirement |
+|--------|----------------------|-----------------|
+| Mix/Hex | OAuth token or API key | Required for OAuth tokens |
+| Gleam | OAuth token or API key | Required for OAuth tokens |
+| Rebar3 | API key (via basic auth) | Not supported |
+
+For OAuth tokens, write operations prompt for a 2FA code which is sent via the `x-hex-otp` header.
+
+### Sequence Diagram
+
+```mermaid
+sequenceDiagram
+ autonumber
+ participant Dev as Developer
+ participant Client as Hex Client
+ participant Local as Local Filesystem
+ participant API as hex.pm API
+ participant S3 as S3 Storage
+ participant Worker as Registry Worker
+
+ Dev->>Client: mix hex.publish / gleam publish
+
+ Note over Client,Local: Build Tarball
+ Client->>Local: Read source files
+ Client->>Client: Generate metadata.config
+ Client->>Client: Create contents.tar.gz
+ Client->>Client: Calculate inner checksum (SHA-256)
+ Client->>Client: Write CHECKSUM file
+ Client->>Client: Create outer tarball
+
+ Note over Client: Tarball structure:
VERSION (3)
metadata.config
contents.tar.gz
CHECKSUM
+
+ Note over Client,API: Authentication
+ Client->>Client: Read credentials from config
+ alt Has OAuth Token
+ Client->>Client: Check token expiry
+ opt Token Expired
+ Client->>API: POST /api/oauth/token (refresh_token grant)
+ API-->>Client: New access_token + refresh_token
+ end
+ Client->>Dev: Prompt for 2FA code
+ Dev-->>Client: TOTP code
+ else Has API Key
+ Note over Client: Use API key directly
+ else No Credentials
+ Note over Client: Initiate OAuth Device Flow
+ Client->>API: See OAuth2 Device Authorization Grant section
+ end
+
+ Note over Client,S3: Upload Package
+ Client->>API: POST /api/publish
Authorization: {token}
x-hex-otp: {2fa_code}
Body: tarball
+
+ API->>API: Validate tarball structure
+ API->>API: Verify checksums
+ API->>API: Check package ownership
+ API->>API: Validate version (semver)
+
+ alt Validation Failed
+ API-->>Client: 422 Unprocessable Entity
+ Client-->>Dev: ❌ Publish failed: {reason}
+ end
+
+ API->>S3: Store tarball at /tarballs/{name}-{version}.tar
+ S3-->>API: Stored
+
+ API->>API: Insert release into database
+ API->>Worker: Trigger registry rebuild
+
+ Worker->>Worker: Rebuild /names protobuf
+ Worker->>Worker: Rebuild /versions protobuf
+ Worker->>Worker: Rebuild /packages/{name} protobuf
+ Worker->>Worker: Sign all with RSA-PKCS1-SHA512
+ Worker->>Worker: Gzip compress
+ Worker->>S3: Upload registry files
+
+ API-->>Client: 201 Created
+ Client-->>Dev: ✓ Package published
+
+ Note over Dev: Optional: Publish docs
+ Dev->>Client: mix hex.docs (automatic)
+ Client->>Client: Generate documentation
+ Client->>API: POST /api/packages/{name}/releases/{version}/docs
Body: docs.tar.gz
+ API->>S3: Store at hexdocs path
+ API-->>Client: 201 Created
+```
+
+---
+
+## 5. Private Package Flow
+
+For organizations with private packages on hex.pm.
+
+### Endpoints
+
+Private packages use repository-scoped endpoints:
+
+| Endpoint | Description |
+|----------|-------------|
+| `/repos/{org}/names` | Package names in organization |
+| `/repos/{org}/versions` | Package versions in organization |
+| `/repos/{org}/packages/{name}` | Package metadata |
+| `/repos/{org}/tarballs/{name}-{version}.tar` | Package tarball |
+
+### Sequence Diagram
+
+```mermaid
+sequenceDiagram
+ autonumber
+ participant Dev as Developer
+ participant Client as Hex Client
+ participant Cache as Local Cache
+ participant CDN as Fastly CDN
+ participant API as hex.pm
+
+ Note over Dev,API: Private Package Fetch
+
+ Dev->>Client: mix deps.get
+
+ Note over Client: Check repository config
+ Client->>Client: Read repo config from mix.exs
+ Client->>Client: Identify private repos (org: "mycompany")
+
+ Note over Client,API: Authenticate for private repo
+ Client->>Cache: Read auth_key for "mycompany" org
+ Cache-->>Client: auth_key
+
+ alt OAuth exchange enabled (default for hex.pm)
+ Client->>API: POST /api/oauth/token
grant_type=client_credentials
Authorization: {auth_key}
+ API-->>Client: Short-lived access_token
+ Client->>Cache: Store token + expiry for org
+ end
+
+ Client->>CDN: GET /repos/mycompany/packages/{name}
Authorization: Bearer {access_token}
+
+ Note over CDN: Private packages NOT cached
(per-user authorization)
+ CDN->>API: Forward with auth
+ API->>API: Verify API key has repo access
+ API-->>CDN: 200 OK + Package data (signed)
+ CDN-->>Client: Package metadata
+
+ Client->>Client: Verify signature
+
+ Note over Client,API: Download private tarball
+ Client->>CDN: GET /repos/mycompany/tarballs/{name}-{version}.tar
Authorization: {api_key}
+ CDN->>API: Forward with auth
+ API-->>CDN: Tarball
+ CDN-->>Client: Tarball
+
+ Client->>Client: Verify checksum
+ Client->>Cache: Store in ~/.hex/packages/mycompany/
+
+ Client-->>Dev: Private dependency fetched
+```
+
+### Security: Untrusted Mirrors
+
+```mermaid
+sequenceDiagram
+ participant Client as Hex Client
+ participant Mirror as Untrusted Mirror
+ participant Hexpm as hex.pm
+
+ Note over Client,Hexpm: ⚠️ CRITICAL: Never send credentials to untrusted mirrors
+
+ Client->>Client: Check mirror configuration
+ Client->>Client: mirror = "https://mirror.example.com"
+
+ alt Public Package
+ Client->>Mirror: GET /packages/{name}
(NO Authorization header)
+ Mirror-->>Client: Package metadata
+ Client->>Client: Verify signature with hex.pm public key
+ else Private Package
+ Note over Client: Private packages MUST use trusted endpoint
+ Client->>Hexpm: GET /repos/{org}/packages/{name}
Authorization: {api_key}
+ Hexpm-->>Client: Package metadata
+ end
+```
+
+---
+
+## 6. OAuth2 Device Authorization Grant
+
+Mix/Hex and Gleam use [RFC 8628 OAuth2 Device Authorization Grant](https://datatracker.ietf.org/doc/html/rfc8628) for interactive authentication. This flow is designed for CLI tools that cannot easily handle browser redirects.
+
+### Supported Clients
+
+| Client | OAuth Support | Fallback |
+|--------|--------------|----------|
+| Mix/Hex | Yes (default) | API keys via `HEX_API_KEY` |
+| Gleam | Yes (default) | API keys via `HEXPM_API_KEY` |
+| Rebar3 | No | Basic auth for API key generation |
+
+### OAuth Endpoints
+
+| Endpoint | Method | Description |
+|----------|--------|-------------|
+| `/api/oauth/device_authorization` | POST | Initiate device flow |
+| `/api/oauth/token` | POST | Exchange codes for tokens / refresh tokens |
+| `/api/oauth/revoke` | POST | Revoke tokens |
+
+### Token Properties
+
+| Property | Value |
+|----------|-------|
+| Access token lifetime | Short-lived (configurable) |
+| Refresh token lifetime | Long-lived |
+| Scopes requested by clients | `mix hex.user auth`: `api repositories` (full API + per-repository scopes). Gleam: `api:write`. |
+| Write operations | Require 2FA via `x-hex-otp` header |
+
+### Sequence Diagram
+
+```mermaid
+sequenceDiagram
+ autonumber
+ participant Dev as Developer
+ participant Client as CLI Client
+ participant Browser as Web Browser
+ participant API as hex.pm API
+
+ Dev->>Client: mix hex.user auth / gleam hex authenticate
+
+ Note over Client,API: Step 1: Device Authorization Request
+ Client->>API: POST /api/oauth/device_authorization
client_id={client_id}
name={client_name}
+ API-->>Client: device_code, user_code,
verification_uri, expires_in, interval
+
+ Note over Client,Browser: Step 2: User Verification
+ Client->>Dev: Display: "Your verification code: XXXXXXXX"
+ Client->>Dev: "Press Enter to open browser..."
+ Dev->>Client: [Enter]
+ Client->>Browser: Open verification_uri
+
+ Note over Dev,API: Step 3: User Authorizes in Browser
+ Dev->>Browser: Navigate to verification page
+ Browser->>API: GET /oauth/device
+ API-->>Browser: Enter code form
+ Dev->>Browser: Enter user_code
+ Browser->>API: POST /oauth/device
+ API-->>Browser: Authorization consent screen
+ Dev->>Browser: Approve scopes
+ Browser->>API: POST /oauth/device/authorize
+ API-->>Browser: Success page
+
+ Note over Client,API: Step 4: Token Polling
+ loop Poll until authorized or expired
+ Client->>API: POST /api/oauth/token
grant_type=urn:ietf:params:oauth:grant-type:device_code
device_code={device_code}
client_id={client_id}
+ alt Authorization Pending
+ API-->>Client: 400 authorization_pending
+ Client->>Client: Sleep for interval seconds
+ else Slow Down
+ API-->>Client: 400 slow_down
+ Client->>Client: Increase polling interval
+ else Access Denied
+ API-->>Client: 403 access_denied
+ Client-->>Dev: ❌ Authorization denied
+ else Expired
+ API-->>Client: 400 expired_token
+ Client-->>Dev: ❌ Code expired, please retry
+ else Success
+ API-->>Client: 200 OK
access_token, refresh_token,
token_type, expires_in
+ end
+ end
+
+ Note over Client: Step 5: Store Credentials
+ Client->>Client: Store tokens in config file
+ Client-->>Dev: ✓ Authenticated successfully
+```
+
+### Token Refresh Flow
+
+```mermaid
+sequenceDiagram
+ autonumber
+ participant Client as CLI Client
+ participant API as hex.pm API
+
+ Client->>Client: Check access_token expiry
+ alt Token expires within 5 minutes
+ Client->>API: POST /api/oauth/token
grant_type=refresh_token
refresh_token={refresh_token}
client_id={client_id}
+ API-->>Client: New access_token, refresh_token,
token_type, expires_in
+ Client->>Client: Update stored tokens
+ end
+ Client->>API: API request with access_token
+```
+
+### Write Operations with 2FA
+
+```mermaid
+sequenceDiagram
+ autonumber
+ participant Dev as Developer
+ participant Client as CLI Client
+ participant API as hex.pm API
+
+ Dev->>Client: mix hex.publish
+
+ Client->>API: POST /api/publish
Authorization: {access_token}
+ API-->>Client: 401 WWW-Authenticate: Bearer realm="hex", error="totp_required"
+
+ Client->>Dev: Enter 2FA code:
+ Dev-->>Client: 123456
+
+ Client->>API: POST /api/publish
Authorization: {access_token}
x-hex-otp: 123456
+ API-->>Client: 201 Created
+```
+
+### Client-Specific Details
+
+#### Mix/Hex
+
+- Client ID: `78ea6566-89fd-481e-a1d6-7d9d78eacca8`
+- Token storage: `~/.hex/hex.config`
+- Commands: `mix hex.user auth`, `mix hex.user deauth`
+
+#### Gleam
+
+- Client ID: `877731e8-cb88-45e1-9b84-9214de7da421`
+- Token storage: `~/.cache/gleam/hex/hexpm/credentials` (refresh token encrypted with user passphrase)
+- Command: `gleam hex authenticate`
+
+---
+
+## Verification Summary
+
+All clients perform these verification steps:
+
+### Registry Verification
+
+1. **Decompress** - gunzip the response
+2. **Decode** - Parse `Signed` protobuf wrapper
+3. **Verify Signature** - RSA-PKCS1-SHA512 of payload using hex.pm public key
+4. **Verify Repository** - Ensure `repository` field matches expected repo name
+5. **Parse Payload** - Decode inner protobuf (Names, Versions, or Package)
+
+### Tarball Verification
+
+1. **Download** - Fetch tarball from `/tarballs/{name}-{version}.tar`
+2. **Outer Checksum** - `SHA256(entire tarball)` must match registry's `outer_checksum`
+3. **Extract** - Unpack tar to get VERSION, metadata.config, contents.tar.gz, CHECKSUM
+4. **Inner Checksum** - Verify CHECKSUM file matches `SHA256(VERSION + metadata.config + contents.tar.gz)`
+
+### Public Key
+
+The hex.pm public key is:
+- Distributed with client libraries (hardcoded)
+- Available at `https://hex.pm/docs/public_keys`
+- 2048-bit RSA key used for RSA-PKCS1-SHA512 signatures
diff --git a/security/threat-model/mitigations.md b/security/threat-model/mitigations.md
new file mode 100644
index 0000000..c168c6b
--- /dev/null
+++ b/security/threat-model/mitigations.md
@@ -0,0 +1,297 @@
+# Mitigations
+
+This document describes the controls that address identified [threats](threats.md).
+
+**Status Legend:**
+- **Implemented** - Control is in place
+- **Partial** - Control exists but has known gaps
+- **Planned** - On roadmap but not yet implemented
+
+## Identity & Access
+
+Addresses: [T1](threats.md#t1-malicious-package-publication), [T4](threats.md#t4-account-takeover)
+
+### Authentication
+
+| Control | Status | Description |
+|---------|--------|-------------|
+| Email verification | Implemented | Users must verify email addresses for account recovery |
+| Password minimum length | Implemented | Minimum 8 characters, no complexity rules |
+| Leaked password detection | Implemented | Checks passwords against HaveIBeenPwned API on login and password change; warns users but allows login |
+| Two-factor authentication (TOTP) | Implemented | Optional for login, required for write operations with OAuth |
+| Phishing-resistant 2FA (WebAuthn) | Planned | Hardware security keys and passkeys |
+| Passwordless authentication | Planned | Passkey-based access methods |
+| OAuth2 Device Authorization Grant | Implemented | Secure CLI authentication flow. See [Client Flows](client-flows.md#6-oauth2-device-authorization-grant) |
+| Login rate limiting | Implemented | 10 attempts per IP per 15 minutes |
+| Mandatory 2FA for maintainers | Planned | Requires rebar3 OAuth migration, then disable basic auth; 2FA already required for OAuth write operations |
+| Critical package MFA | Partial | Require MFA for maintainers of high-impact packages |
+| Abandoned domain detection | Planned | Detect and disable account recovery via expired email domains |
+| Security notifications | Implemented | Alert maintainers about critical account changes via email |
+| Account recovery policy | Planned | Documented procedures for account access restoration |
+
+### Token Management
+
+| Control | Status | Description |
+|---------|--------|-------------|
+| Scoped API tokens | Implemented | Tokens can be scoped by domain (api, repository, package, docs) and resource (read/write, specific repos/packages) |
+| Short-lived OAuth access tokens | Implemented | Access tokens expire quickly, refresh tokens for renewal |
+| Token revocation | Implemented | Users can revoke tokens at any time |
+| API key expiry dates | Implemented | Allow setting expiration on API keys |
+| Token prefixing | Planned | Distinctive repository identifiers on all tokens |
+| Secret scanning integration | Planned | Tokens compatible with third-party secret detection tools with automated revocation |
+| 2FA for write operations | Implemented | OAuth tokens require 2FA for publishing. See [Client Flows](client-flows.md#write-operations-with-2fa) |
+
+### Session Security
+
+| Control | Status | Description |
+|---------|--------|-------------|
+| Secure session cookies | Implemented | Phoenix default secure cookie configuration |
+| Session timeout | Implemented | Automatic session expiration |
+| Session invalidation | Implemented | Logout invalidates session server-side |
+| Sudo mode | Implemented | Critical operations require re-authentication; shorter lifetime than regular session |
+
+## Publishing Controls
+
+Addresses: [T1](threats.md#t1-malicious-package-publication), [T2](threats.md#t2-typosquatting--dependency-confusion)
+
+### Ownership Model
+
+| Control | Status | Description |
+|---------|--------|-------------|
+| Package ownership required | Implemented | Only owners can publish to a package |
+| Owner levels | Implemented | "full" (can manage owners) vs "maintainer" (can publish only) |
+| Transfer confirmation | Implemented | Ownership transfers require confirmation |
+
+### Audit Trail
+
+| Control | Status | Description |
+|---------|--------|-------------|
+| Comprehensive audit logging | Implemented | Logs: releases (publish/revert/retire), ownership changes, key operations, password changes, email changes, billing, sessions, 2FA changes |
+| Audit log metadata | Implemented | Includes user agent, remote IP, key/token used, user data snapshot |
+| Package audit logs | Implemented | Viewable per-package in dashboard |
+| User audit logs | Implemented | Viewable per-user in dashboard |
+
+### Version Immutability
+
+| Control | Status | Description |
+|---------|--------|-------------|
+| Immutable versions | Implemented | Published versions cannot be modified after grace period |
+| Retirement (not deletion) | Implemented | Packages can be retired but not deleted |
+
+## Supply Chain Integrity
+
+Addresses: [T3](threats.md#t3-package-tampering)
+
+### Registry Signing
+
+| Control | Status | Description |
+|---------|--------|-------------|
+| RSA-PKCS1-SHA512 signatures | Implemented | All registry files are signed |
+| Public key distribution | Implemented | Public key bundled with clients |
+| Client signature verification | Implemented | Clients verify before trusting metadata. See [Client Flows](client-flows.md#verification-summary) |
+
+### Checksums
+
+| Control | Status | Description |
+|---------|--------|-------------|
+| Outer checksum (SHA-256) | Implemented | Tarball integrity verification |
+| Checksums in signed registry | Implemented | Checksums protected by registry signature |
+| Client verification | Implemented | Clients verify checksums before extraction |
+
+### Build Provenance
+
+| Control | Status | Description |
+|---------|--------|-------------|
+| Trusted Publishing (OIDC) | Planned | CI provider integration for keyless publishing |
+| Build attestations (SLSA) | Planned | Cryptographic proof of build origin |
+| Source repository linking | Partial | Links exist but not cryptographically verified |
+
+See [Supply Chain - Provenance](../supply-chain/provenance.md).
+
+## Ecosystem Protections
+
+Addresses: [T2](threats.md#t2-typosquatting--dependency-confusion)
+
+### Namespace Controls
+
+| Control | Status | Description |
+|---------|--------|-------------|
+| Globally unique names | Implemented | Package names are unique across the registry |
+| Reserved names | Implemented | Common names like "hex", "elixir", "erlang", "otp" are reserved |
+| Squatting policies | Implemented | Names can be reclaimed if squatted |
+
+### Typosquatting Detection
+
+| Control | Status | Description |
+|---------|--------|-------------|
+| Levenshtein distance check | Implemented | Daily job checks new packages against existing names; emails moderators when candidates found |
+| Automated blocking | Accepted Risk | Detection is alert-only; does not block publishing |
+
+### Malicious Package Detection
+
+| Control | Status | Description |
+|---------|--------|-------------|
+| Malicious package scanning | Planned | Automated scanning of packages for known malicious patterns and file hashes |
+| Malicious package disclosure (OSV) | Planned | Malicious packages disclosed to OSV database |
+
+### Community Reporting
+
+| Control | Status | Description |
+|---------|--------|-------------|
+| Report mechanism (UI) | Planned | Users can report suspicious packages via web UI |
+| Report mechanism (CLI) | Planned | Users can report suspicious packages via CLI |
+| Report mechanism (API) | Planned | Users can report suspicious packages via API |
+| Review process | Planned | Reports are reviewed by operators |
+
+## Documentation Isolation
+
+Addresses: [T5](threats.md#t5-documentation-based-attacks)
+
+### Origin Separation
+
+| Control | Status | Description |
+|---------|--------|-------------|
+| Separate origin | Implemented | Documentation served from hexdocs.pm |
+| Per-package origin isolation | Planned | Each package's docs served from separate origin to prevent cross-package attacks |
+| No shared authentication | Implemented | hexdocs.pm has no access to registry sessions |
+
+### Content Security
+
+| Control | Status | Description |
+|---------|--------|-------------|
+| Content Security Policy | Implemented | CSP headers with Sentry violation reporting |
+| README sandboxing | Implemented | READMEs rendered in isolated iframe with restricted CSP |
+| Content sanitization | Implemented | HTML sanitizer for user-provided content |
+
+## Infrastructure Security
+
+Addresses: [T6](threats.md#t6-registry-infrastructure-compromise)
+
+### Access Control
+
+| Control | Status | Description |
+|---------|--------|-------------|
+| Least privilege | Partial | Infrastructure access limited to a small set of operators; Kubernetes RBAC enforced; OIDC federation scopes CI service account permissions |
+| Role-based access | Implemented | User roles: "basic", "mod" |
+
+See [Operations - Access Control](../operations/access-control.md).
+
+### Security Policy
+
+| Control | Status | Description |
+|---------|--------|-------------|
+| Vulnerability disclosure policy | Implemented | Published policy allowing security researchers to report issues with legal safe harbor |
+
+### Network Security
+
+| Control | Status | Description |
+|---------|--------|-------------|
+| Service isolation | Implemented | Services separated where possible |
+| TLS everywhere | Implemented | All external communication encrypted |
+
+### Monitoring
+
+| Control | Status | Description |
+|---------|--------|-------------|
+| Security event monitoring | Implemented | Security-relevant events are monitored |
+| CSP violation reporting | Implemented | CSP violations reported to Sentry |
+| Event transparency logs | Planned | Published activity records enabling anomaly detection |
+| Security infrastructure reviews | Planned | Periodic assessments of repository systems |
+
+## Availability
+
+Addresses: [T7](threats.md#t7-denial-of-service)
+
+### Rate Limiting
+
+| Control | Status | Description |
+|---------|--------|-------------|
+| API rate limits (authenticated) | Implemented | 500 requests per user per minute |
+| API rate limits (unauthenticated) | Implemented | 100 requests per IP per minute |
+| Organization rate limits | Implemented | 500 requests per organization per minute |
+| Login rate limits | Implemented | 10 attempts per IP per 15 minutes |
+| 2FA rate limits | Implemented | 20 attempts per IP per 15 minutes; 5 per session per 10 minutes |
+| Sudo mode rate limits | Implemented | 5 password attempts per user per 15 minutes; 5 2FA attempts per user per 15 minutes |
+| Device verification limits | Implemented | 10 per user, 30 per IP per 15 minutes |
+| IP allow/block lists | Implemented | Configurable address filtering |
+| Upload size limits | Implemented | Maximum package size enforced |
+
+### CDN
+
+| Control | Status | Description |
+|---------|--------|-------------|
+| Fastly CDN | Implemented | Global edge caching for package distribution |
+| Edge caching | Implemented | Reduces origin load, improves availability |
+
+### Operational
+
+| Control | Status | Description |
+|---------|--------|-------------|
+| Monitoring and alerting | Implemented | Availability monitoring in place |
+| Incident response | Implemented | Documented procedures. See [Operations - Incident Response](../operations/incident-response.md) |
+
+## Dependency Security
+
+Addresses: [T8](threats.md#t8-vulnerable-dependencies-transitive)
+
+### Vulnerability Tracking
+
+| Control | Status | Description |
+|---------|--------|-------------|
+| Advisory database integration | Partial | Hex.pm ingests OSV advisory data and surfaces it on the website; clients (Mix, Rebar3, Gleam) do not yet consume advisories |
+| Hex.pm as CNA | Implemented | Can issue CVEs for Elixir/Erlang packages via EEF CNA |
+
+See [SDLC - Secure Process](../sdlc/process.md#vulnerability-handling).
+
+### User Tools
+
+| Control | Status | Description |
+|---------|--------|-------------|
+| `mix hex.audit` (retirement) | Implemented | CLI tool checks for retired packages |
+| `mix hex.audit` (vulnerabilities) | Planned | CLI tool to check for known vulnerabilities |
+| Dependency tree visibility | Implemented | Transitive dependencies shown in metadata |
+| Security advisories on hex.pm | Implemented | Advisories displayed on package pages at `/packages/:name/advisories` |
+| Hash/version pinning | Implemented | Dependencies can be locked to specific versions and checksums via lock files |
+| SBOM generation | Implemented | Software Bill of Materials documentation |
+| Automated remediation | Planned | Upgrade dependencies to resolve known vulnerabilities |
+| Reachability analysis | Planned | Reduce false positives by determining if vulnerable code paths execute |
+
+## Ecosystem Health
+
+Addresses: [T9](threats.md#t9-unmaintainedabandoned-packages)
+
+### Package Metadata
+
+| Control | Status | Description |
+|---------|--------|-------------|
+| Last activity indicators | Implemented | Shows when package was last updated |
+| Retirement status | Implemented | Packages can be marked as retired. See [Package Metadata](../../package_metadata.md) |
+
+### Community Signals
+
+| Control | Status | Description |
+|---------|--------|-------------|
+| Download statistics | Implemented | Shows package popularity |
+| Maintenance activity | Implemented | Visible update history |
+
+### Succession Planning
+
+| Control | Status | Description |
+|---------|--------|-------------|
+| Ownership transfer | Implemented | Mechanism to transfer packages |
+| Abandoned package adoption | Partial | Process exists but not formalized |
+
+## Mitigation Coverage Matrix
+
+| Threat | Primary Mitigations | Status | Notes |
+|--------|---------------------|--------|-------|
+| T1: Malicious publication | 2FA, token scoping, audit logs | Implemented | 2FA optional for login |
+| T2: Typosquatting | Levenshtein check, community reports | Partial | Detection is alert-only |
+| T3: Package tampering | Signatures, checksums | Implemented | Strong coverage |
+| T4: Account takeover | 2FA, OAuth, leaked password check, rate limiting | Implemented | 2FA optional for login |
+| T5: Documentation attacks | Origin separation, CSP, sandboxing | Implemented | Strong coverage |
+| T6: Registry compromise | Access control, monitoring | Implemented | Strong coverage |
+| T7: DoS | Rate limiting, CDN | Implemented | Strong coverage |
+| T8: Vulnerable dependencies | OSV ingestion, advisories pages, CNA | Partial | Clients do not yet consume advisories |
+| T9: Unmaintained packages | Metadata, retirement status | Partial | Succession process informal |
+| T10: Build pipeline compromise | (Planned: Trusted Publishing) | Planned | Gap - highest priority |
diff --git a/security/threat-model/overview.md b/security/threat-model/overview.md
new file mode 100644
index 0000000..997f88e
--- /dev/null
+++ b/security/threat-model/overview.md
@@ -0,0 +1,85 @@
+# Threat Model Overview
+
+This document describes the threat modelling approach for the Hex package ecosystem.
+
+## Scope
+
+This threat model covers:
+
+- **hex.pm** - The package registry API and web interface
+- **hexdocs.pm** - Documentation hosting
+- **repo.hex.pm** - Package artifact and registry storage
+- **Hex clients** - Mix, Rebar3, and Gleam build tool integrations
+
+## Methodology
+
+This threat model uses a hybrid approach:
+
+1. **Asset-based analysis** - Identify what we protect
+2. **Actor-based analysis** - Identify who interacts with the system
+3. **Trust boundary analysis** - Identify where trust changes
+4. **Threat enumeration** - Identify what can go wrong
+
+## Framework Alignment
+
+This threat model draws from established supply chain security frameworks:
+
+| Framework | Focus | Reference |
+|-----------|-------|-----------|
+| ENISA | Package manager security risks | [Technical Advisory for Secure Use of Package Managers](https://www.enisa.europa.eu/publications/enisa-technical-advisory-for-secure-use-of-package-managers) |
+| OpenSSF | Repository security principles | [Principles for Package Repository Security](https://repos.openssf.org/) |
+| OWASP | Application security risks | [Top 10:2025 A03 - Software Supply Chain Failures](https://owasp.org/Top10/) |
+| NIST SSDF | Secure development practices | [SP 800-218](https://csrc.nist.gov/publications/detail/sp/800-218/final) |
+| SLSA | Supply chain integrity levels | [SLSA Specification](https://slsa.dev/) |
+
+## Threat Summary
+
+| ID | Threat | Likelihood | Impact | Risk |
+|----|--------|------------|--------|------|
+| T1 | Malicious publication | Medium | Critical | High |
+| T2 | Typosquatting | Medium | High | Medium |
+| T3 | Package tampering | Low | Critical | Medium |
+| T4 | Account takeover | Medium | High | High |
+| T5 | Documentation attacks | Low | Medium | Low |
+| T6 | Registry compromise | Low | Critical | Medium |
+| T7 | Denial of service | Medium | Medium | Medium |
+| T8 | Vulnerable dependencies | High | Variable | High |
+| T9 | Unmaintained packages | High | Medium | Medium |
+| T10 | Build pipeline compromise | Low | Critical | Medium |
+
+See [Threats](./threats.md) for detailed descriptions.
+
+## Document Structure
+
+| Document | Purpose |
+|----------|---------|
+| [Architecture](./architecture.md) | System overview and trust boundaries |
+| [Assets](./assets.md) | What we protect |
+| [Actors](./actors.md) | Legitimate users and adversaries |
+| [Threats](./threats.md) | Key threats to the ecosystem |
+| [Mitigations](./mitigations.md) | How threats are addressed |
+| [Assumptions](./assumptions.md) | What we assume and don't guarantee |
+
+## Hex-Specific Considerations
+
+### Registry Role
+
+Hex.pm is the distribution point, not the build system. This means:
+
+- **Limited control over T10**: Build happens on maintainer machines
+- **Strong control over T3**: Registry signing and checksums provide tamper evidence
+- **Shared responsibility for T1/T4**: Authentication controls, but maintainers control their credentials
+
+### Elixir/Erlang Ecosystem Factors
+
+- **BEAM immutability**: Less attack surface than native code execution
+- **Smaller ecosystem**: Fewer packages means potentially less noise for detection
+- **Active community**: Strong review culture in Elixir community
+
+## Maintenance
+
+This threat model is a living document. It should be reviewed:
+
+- When significant features are added
+- When new threat vectors are identified
+- Periodically (at least annually)
diff --git a/security/threat-model/threats.md b/security/threat-model/threats.md
new file mode 100644
index 0000000..121eae6
--- /dev/null
+++ b/security/threat-model/threats.md
@@ -0,0 +1,452 @@
+# Threats
+
+This document enumerates key threats to the Hex ecosystem. See [Overview](./overview.md) for methodology and framework references.
+
+## T1: Malicious Package Publication
+
+### Description
+
+An attacker publishes a package containing malicious code designed to harm users or exfiltrate data.
+
+### Attack Vectors
+
+| Vector | Description | ENISA Category |
+|--------|-------------|----------------|
+| Compromised maintainer | Attacker gains access to legitimate maintainer account | Supply chain attacks |
+| Malicious maintainer | Insider threat from package owner | Supply chain attacks |
+| Compromised CI/CD | Attack on maintainer's build/publish pipeline | Supply chain attacks |
+| Social engineering | Convincing maintainer to add malicious contributor | Supply chain attacks |
+
+### Real-World Examples
+
+- **event-stream (npm, 2018)**: Maintainer transferred ownership; new owner added malicious code targeting cryptocurrency wallets
+- **ua-parser-js (npm, 2021)**: Compromised maintainer account used to publish crypto-mining malware
+- **ctx/phpass (PyPI, 2022)**: Dormant packages hijacked via expired maintainer email domains
+- **Shai-Hulud (npm, 2025)**: Self-replicating worm via compromised accounts; exploited post-install scripts to propagate
+- **LiteLLM (PyPI, 2026)**: Compromised package delivering multi-stage credential stealer
+- **RubyGems credential campaign (2025)**: 60+ malicious gems stealing social media credentials
+
+### Impact
+
+| Dimension | Assessment |
+|-----------|------------|
+| Severity | Critical |
+| Scope | All users who install the package |
+| Effect | Arbitrary code execution, data exfiltration, supply chain propagation |
+
+### Framework Alignment
+
+| Framework | Reference |
+|-----------|-----------|
+| ENISA | Section 3.2 - Supply chain attacks |
+| OpenSSF | Account Compromise, Package Manipulation |
+| OWASP A03 | Malicious packages |
+| SSDF | PS.1 (Protect code), PS.2 (Integrity verification) |
+
+### Related Controls
+
+See [Mitigations](./mitigations.md#identity--access) for controls.
+
+## T2: Typosquatting / Dependency Confusion
+
+### Description
+
+An attacker publishes packages with names designed to be confused with legitimate packages, either through typographical similarity or namespace collision.
+
+### Attack Vectors
+
+| Vector | Description | ENISA Category |
+|--------|-------------|----------------|
+| Typosquatting | Similar names: `pheonix` vs `phoenix` | Typosquatting |
+| Combosquatting | Adding prefixes/suffixes: `phoenix-utils` | Typosquatting |
+| Dependency confusion | Internal package name collision with public registry | Namespace confusion |
+| Namespace squatting | Claiming names before legitimate projects | Typosquatting |
+| Slopsquatting | Registering packages that LLMs hallucinate | AI-assisted attacks |
+
+### Real-World Examples
+
+- **Dependency confusion attacks (2021)**: Researcher Alex Birsan demonstrated attacks on Apple, Microsoft, PayPal using internal package names
+- **crossenv (npm, 2017)**: Typosquat of `cross-env` with credential-stealing code
+- **python3-dateutil (PyPI, 2019)**: Typosquat of `python-dateutil` with malicious payload
+- **huggingface-cli (PyPI, 2024)**: Researcher registered AI-hallucinated package name; received 30,000+ downloads in 3 months
+
+### Impact
+
+| Dimension | Assessment |
+|-----------|------------|
+| Severity | High |
+| Scope | Users who mistype, misconfigure, or trust AI-generated dependencies |
+| Effect | Installation of attacker-controlled code |
+
+### AI-Assisted Attack Vector (Slopsquatting)
+
+LLMs used for code generation hallucinate nonexistent package names at significant rates:
+
+| Finding | Source |
+|---------|--------|
+| 19.7% of 2.23M code samples contained hallucinated packages | [USENIX 2024](https://www.usenix.org/publications/loginonline/we-have-package-you-comprehensive-analysis-package-hallucinations-code) |
+| 205,474 unique nonexistent packages identified in testing | USENIX 2024 |
+| ~45% of hallucinated packages regenerate consistently | USENIX 2024 |
+| Open-source models: ~21% hallucination rate vs commercial ~5% | [arXiv 2501.19012](https://arxiv.org/html/2501.19012v1) |
+
+Attackers can monitor LLM outputs, identify consistently hallucinated package names, and register them with malicious code. The predictability of hallucinations (same prompts produce same fake packages) makes this attack scalable.
+
+### Framework Alignment
+
+| Framework | Reference |
+|-----------|-----------|
+| ENISA | Section 3.2.3 - Typosquatting, Section 3.2.4 - Namespace confusion |
+| OpenSSF | Ecosystem Threats |
+| OWASP A03 | Dependency confusion |
+| SSDF | PW.4 (Reuse existing well-secured software) |
+
+### Related Controls
+
+See [Mitigations](./mitigations.md#ecosystem-protections) for controls.
+
+## T3: Package Tampering
+
+### Description
+
+An attacker modifies package artifacts after publication, either in transit or at rest.
+
+### Attack Vectors
+
+| Vector | Description | ENISA Category |
+|--------|-------------|----------------|
+| Storage compromise | Unauthorized access to S3, CDN, or origin servers | Infrastructure attacks |
+| Man-in-the-middle | Interception and modification during download | Infrastructure attacks |
+| Cache poisoning | Corrupting CDN or proxy caches | Infrastructure attacks |
+| Mirror compromise | Attacking unofficial mirrors | Infrastructure attacks |
+
+### Real-World Examples
+
+- **Codecov (2021)**: Bash uploader script modified to exfiltrate CI environment variables
+- **PHP Git server (2021)**: Unauthorized commits to PHP source with backdoor
+- **Gentoo GitHub (2018)**: Repository compromise with malicious ebuilds
+
+### Impact
+
+| Dimension | Assessment |
+|-----------|------------|
+| Severity | Critical |
+| Scope | All users who download tampered packages |
+| Effect | Code different from what maintainer published |
+
+### Framework Alignment
+
+| Framework | Reference |
+|-----------|-----------|
+| ENISA | Section 3.2.2 - Compromised legitimate packages |
+| OpenSSF | Infrastructure Threats |
+| OWASP A03 | Insufficient integrity verification |
+| SSDF | PS.2 (Integrity verification), PS.3 (Archive releases) |
+| SLSA | Build Track L2-L4 (Tamper resistance) |
+
+### Related Controls
+
+See [Mitigations](./mitigations.md#supply-chain-integrity) and [Supply Chain - Verification](../supply-chain/verification.md).
+
+## T4: Account Takeover
+
+### Description
+
+An attacker gains unauthorized access to a maintainer or administrator account.
+
+### Attack Vectors
+
+| Vector | Description | ENISA Category |
+|--------|-------------|----------------|
+| Credential reuse | Password from other breaches | Supply chain attacks |
+| Phishing | Fake login pages, OAuth consent abuse | Supply chain attacks |
+| Token leakage | API keys in logs, repos, screenshots | Supply chain attacks |
+| Session hijacking | Cookie theft, XSS exploitation | Supply chain attacks |
+| Email domain expiry | Takeover of expired maintainer email domains | Supply chain attacks |
+
+### Real-World Examples
+
+- **ua-parser-js (2021)**: npm account compromised via credential stuffing
+- **coa/rc (npm, 2021)**: Maintainer account compromised, malicious versions published
+- **PyPI ctx (2022)**: Account recovered via expired email domain
+
+### Impact
+
+| Dimension | Assessment |
+|-----------|------------|
+| Severity | High to Critical (depends on account privileges) |
+| Scope | Packages owned by compromised account |
+| Effect | Unauthorized publishing, package takeover, ecosystem-wide impact for admins |
+
+### Framework Alignment
+
+| Framework | Reference |
+|-----------|-----------|
+| ENISA | Section 3.2.2 - Compromised legitimate packages |
+| OpenSSF | Account Compromise |
+| OWASP A03 | Compromised maintainer accounts |
+| SSDF | PO.5 (Secure environments), PS.1 (Protect code) |
+
+### Related Controls
+
+See [Mitigations](./mitigations.md#identity--access) for controls.
+
+## T5: Documentation-Based Attacks
+
+### Description
+
+An attacker exploits documentation hosting to attack users viewing package documentation.
+
+### Attack Vectors
+
+| Vector | Description |
+|--------|-------------|
+| Cross-site scripting (XSS) | Malicious scripts in documentation HTML |
+| JavaScript injection | Exploiting documentation rendering |
+| Phishing via docs | Fake login forms or credential harvesting |
+| Malicious links | Links to malware or phishing sites |
+
+### Impact
+
+| Dimension | Assessment |
+|-----------|------------|
+| Severity | Medium |
+| Scope | Users viewing malicious documentation |
+| Effect | Session theft, credential phishing, malware distribution |
+
+### Framework Alignment
+
+| Framework | Reference |
+|-----------|-----------|
+| OpenSSF | User Interface Security |
+| OWASP | A03 (XSS in documentation systems) |
+
+### Related Controls
+
+See [Mitigations](./mitigations.md#documentation-isolation) for controls.
+
+## T6: Registry Infrastructure Compromise
+
+### Description
+
+An attacker gains access to registry infrastructure, enabling wide-scale attacks.
+
+### Attack Vectors
+
+| Vector | Description | ENISA Category |
+|--------|-------------|----------------|
+| Application vulnerability | Exploiting bugs in registry software | Infrastructure attacks |
+| Insider threat | Malicious or compromised operator | Supply chain attacks |
+| Cloud provider compromise | Attack on underlying infrastructure | Infrastructure attacks |
+| Supply chain on registry | Attack on registry's dependencies | Supply chain attacks |
+
+### Real-World Examples
+
+- **RubyGems (2013)**: Vulnerability allowed arbitrary gem replacement
+- **npm (2018)**: Credential leak affecting old packages
+- **PyPI (2022)**: Phishing campaign targeting maintainers
+
+### Impact
+
+| Dimension | Assessment |
+|-----------|------------|
+| Severity | Critical |
+| Scope | Entire ecosystem |
+| Effect | Full control over package distribution |
+
+### Framework Alignment
+
+| Framework | Reference |
+|-----------|-----------|
+| ENISA | Section 3.2.2 - Compromised legitimate packages |
+| OpenSSF | Infrastructure Threats |
+| OWASP A03 | Build pipeline compromise |
+| SSDF | PO.5 (Secure environments), PS.1 (Protect code) |
+
+### Related Controls
+
+See [Mitigations](./mitigations.md#infrastructure-security) and [Operations](../operations/access-control.md).
+
+## T7: Denial of Service
+
+### Description
+
+An attacker degrades or disrupts registry availability.
+
+### Attack Vectors
+
+| Vector | Description |
+|--------|-------------|
+| Volumetric attacks | DDoS flooding |
+| Resource exhaustion | Large uploads, expensive queries |
+| Application-layer attacks | Exploiting API rate limits |
+| Dependency on registry | CI/CD pipelines blocked during outage |
+
+### Impact
+
+| Dimension | Assessment |
+|-----------|------------|
+| Severity | Medium to High |
+| Scope | All users during outage |
+| Effect | Unable to publish or install packages, CI/CD failures |
+
+### Framework Alignment
+
+| Framework | Reference |
+|-----------|-----------|
+| OpenSSF | Infrastructure availability |
+| SSDF | PO.5 (Environment availability) |
+
+### Related Controls
+
+See [Mitigations](./mitigations.md#availability) for controls.
+
+## T8: Vulnerable Dependencies (Transitive)
+
+### Description
+
+Packages contain known vulnerabilities, either directly or through transitive dependencies, that expose users to security risks.
+
+### Attack Vectors
+
+| Vector | Description | ENISA Category |
+|--------|-------------|----------------|
+| Direct vulnerabilities | Known CVEs in direct dependencies | Inherent vulnerabilities |
+| Transitive vulnerabilities | Vulnerabilities in dependencies of dependencies | Inherent vulnerabilities |
+| Outdated dependencies | Using versions with known security issues | Inherent vulnerabilities |
+| Unpatched vulnerabilities | Maintainer not addressing reported issues | Unmaintained packages |
+
+### Real-World Examples
+
+- **Log4Shell (2021)**: CVE-2021-44228 affected thousands of applications through transitive dependencies
+- **left-pad (2016)**: Unpublishing broke thousands of builds (availability, not security)
+- **colors.js/faker.js (2022)**: Maintainer sabotage affecting downstream users
+
+### Impact
+
+| Dimension | Assessment |
+|-----------|------------|
+| Severity | Variable (depends on vulnerability) |
+| Scope | All users of affected dependency chain |
+| Effect | Inherited vulnerabilities, delayed patching |
+
+### Framework Alignment
+
+| Framework | Reference |
+|-----------|-----------|
+| ENISA | Section 3.1 - Packages with inherent vulnerabilities |
+| OpenSSF | Dependency Security |
+| OWASP A03 | Third-party component vulnerabilities |
+| SSDF | PW.4 (Verify third-party components), RV.1 (Identify vulnerabilities) |
+
+### Related Controls
+
+See [Mitigations](./mitigations.md#dependency-security) and [SDLC - Secure Build](../sdlc/build.md#dependencies).
+
+## T9: Unmaintained/Abandoned Packages
+
+### Description
+
+Packages that are no longer actively maintained pose increasing security risks over time.
+
+### Attack Vectors
+
+| Vector | Description | ENISA Category |
+|--------|-------------|----------------|
+| Unpatched vulnerabilities | No security updates for discovered issues | Unmaintained packages |
+| Stale dependencies | Outdated transitive dependencies | Unmaintained packages |
+| Account recovery attacks | Takeover of abandoned accounts/domains | Supply chain attacks |
+| Compatibility issues | Breaking changes in runtime/ecosystem | Unmaintained packages |
+
+### Real-World Examples
+
+- **event-stream (2018)**: Maintenance transferred to malicious actor due to maintainer burnout
+- **request (npm)**: Deprecated but still widely used, no security patches
+- **PyPI ctx (2022)**: Abandoned package hijacked via expired email domain
+
+### Impact
+
+| Dimension | Assessment |
+|-----------|------------|
+| Severity | Medium (increasing over time) |
+| Scope | Users depending on unmaintained packages |
+| Effect | Accumulating technical debt, security exposure |
+
+### Framework Alignment
+
+| Framework | Reference |
+|-----------|-----------|
+| ENISA | Section 3.1.2 - Unmaintained packages |
+| OpenSSF | Ecosystem Health |
+| SSDF | PW.4.4 (Verify components throughout lifecycle) |
+
+### Related Controls
+
+See [Mitigations](./mitigations.md#ecosystem-health) for controls.
+
+## T10: Build Pipeline Compromise (Client-Side)
+
+### Description
+
+An attacker compromises the build or CI/CD pipeline of package maintainers, injecting malicious code before it reaches the registry.
+
+### Attack Vectors
+
+| Vector | Description |
+|--------|-------------|
+| CI/CD credential theft | Stealing publish tokens from CI systems |
+| Build system compromise | Modifying build scripts or dependencies |
+| Source repository attacks | Compromising GitHub/GitLab accounts |
+| IDE/toolchain attacks | Malicious IDE extensions or build tools |
+| Build cache poisoning | Injecting malicious artifacts into CI cache layers |
+
+### Real-World Examples
+
+- **SolarWinds (2020)**: Build system compromise injected backdoor into signed software
+- **Codecov (2021)**: CI script modified to exfiltrate secrets
+- **GitHub Actions supply chain**: Attackers targeting reusable workflows
+- **Ultralytics (PyPI, 2024)**: GitHub Actions workflow compromised; build cache poisoned during compilation
+
+### Impact
+
+| Dimension | Assessment |
+|-----------|------------|
+| Severity | Critical |
+| Scope | All users of packages built via compromised pipeline |
+| Effect | Malicious code in legitimately-signed packages |
+
+### Framework Alignment
+
+| Framework | Reference |
+|-----------|-----------|
+| OpenSSF | Build Integrity |
+| OWASP A03 | Build pipeline compromise |
+| SSDF | PO.3 (Toolchain security), PO.5 (Secure environments) |
+| SLSA | Build Track (all levels) |
+
+### Related Controls
+
+See [Build Provenance](./mitigations.md#build-provenance) under Supply Chain Integrity and [Supply Chain - Provenance](../supply-chain/provenance.md).
+
+## Framework Cross-Reference
+
+| Threat | ENISA Section | OpenSSF Category | OWASP A03 | SSDF Practices |
+|--------|---------------|------------------|-----------|----------------|
+| T1 | 3.2 Supply chain | Account Compromise, Package Manipulation | Malicious packages | PS.1, PS.2 |
+| T2 | 3.2.3-4 Typosquatting, Namespace confusion | Ecosystem Threats | Dependency confusion | PW.4 |
+| T3 | 3.2.2 Compromised packages | Infrastructure Threats | Insufficient integrity | PS.2, PS.3 |
+| T4 | 3.2.2 Compromised packages | Account Compromise | Compromised accounts | PO.5, PS.1 |
+| T5 | - | User Interface Security | XSS | - |
+| T6 | 3.2.2 Compromised packages | Infrastructure Threats | Build pipeline | PO.5, PS.1 |
+| T7 | - | Infrastructure Availability | - | PO.5 |
+| T8 | 3.1 Inherent vulnerabilities | Dependency Security | Component vulnerabilities | PW.4, RV.1 |
+| T9 | 3.1.2 Unmaintained packages | Ecosystem Health | - | PW.4.4 |
+| T10 | - | Build Integrity | Build pipeline | PO.3, PO.5, SLSA |
+
+## Future Threats Under Monitoring
+
+| Threat | Description | Status |
+|--------|-------------|--------|
+| AI-generated malicious code | LLM-generated packages designed to evade detection | Monitoring |
+| Quantum cryptography threats | Future impact on registry signing | Long-term |
+| EU CRA requirements | Potential regulatory compliance requirements | Monitoring |
+