From 781b2da6bbd6bead72faa5fa98b2531ed6a46d14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonatan=20M=C3=A4nnchen?= Date: Tue, 6 Jan 2026 14:58:57 +0100 Subject: [PATCH 1/2] Security Documentation --- README.md | 6 + security/README.md | 58 ++ security/operations/access-control.md | 54 ++ security/operations/incident-response.md | 96 +++ security/sdlc/README.md | 47 ++ security/sdlc/build.md | 101 ++++ security/sdlc/exception-register.md | 39 ++ security/sdlc/process.md | 131 +++++ security/sdlc/risk-register.md | 43 ++ security/sdlc/runtime.md | 80 +++ security/supply-chain/overview.md | 93 +++ security/supply-chain/provenance.md | 107 ++++ security/supply-chain/signing.md | 158 +++++ security/supply-chain/verification.md | 171 ++++++ security/threat-model/actors.md | 91 +++ security/threat-model/architecture.md | 320 ++++++++++ security/threat-model/assets.md | 142 +++++ security/threat-model/assumptions.md | 114 ++++ security/threat-model/client-flows.md | 715 +++++++++++++++++++++++ security/threat-model/mitigations.md | 297 ++++++++++ security/threat-model/overview.md | 85 +++ security/threat-model/threats.md | 452 ++++++++++++++ 22 files changed, 3400 insertions(+) create mode 100644 security/README.md create mode 100644 security/operations/access-control.md create mode 100644 security/operations/incident-response.md create mode 100644 security/sdlc/README.md create mode 100644 security/sdlc/build.md create mode 100644 security/sdlc/exception-register.md create mode 100644 security/sdlc/process.md create mode 100644 security/sdlc/risk-register.md create mode 100644 security/sdlc/runtime.md create mode 100644 security/supply-chain/overview.md create mode 100644 security/supply-chain/provenance.md create mode 100644 security/supply-chain/signing.md create mode 100644 security/supply-chain/verification.md create mode 100644 security/threat-model/actors.md create mode 100644 security/threat-model/architecture.md create mode 100644 security/threat-model/assets.md create mode 100644 security/threat-model/assumptions.md create mode 100644 security/threat-model/client-flows.md create mode 100644 security/threat-model/mitigations.md create mode 100644 security/threat-model/overview.md create mode 100644 security/threat-model/threats.md 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..86dcf3c --- /dev/null +++ b/security/operations/access-control.md @@ -0,0 +1,54 @@ +# 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 + +- CI/CD uses OIDC workload identity federation (no long-lived service account keys) +- 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..f7ac959 --- /dev/null +++ b/security/sdlc/build.md @@ -0,0 +1,101 @@ +# 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-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) + +| Stage | Method | +|-------|--------| +| GCP authentication | Workload Identity Federation (OIDC) | +| Container Registry | OAuth2 access token | +| No long-lived secrets | Short-lived tokens from OIDC | + +## 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..fc1dcc8 --- /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 | 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..061605c --- /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 | Mitigation | Reference | +|----|------|----------|--------|------------|-----------| +| R-001 | Basic Authentication maintained for backward compatibility | Medium | Mitigating | OAuth2 migration planned; rate limiting in place | Security Audit 2026 | +| R-002 | Documentation hosted as full websites (HTML/JS) | Low | Accepted | Malicious content removed upon report | Security Audit 2026 | +| R-003 | User enumeration via API | Low | Accepted | Users are public for package publication; profile info is user-provided | Security Audit 2026 | +| R-004 | No WAF | Low | Accepted | 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..4417259 --- /dev/null +++ b/security/sdlc/runtime.md @@ -0,0 +1,80 @@ +# 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 | GitHub secrets | OIDC workload identity | +| Database credentials | Runtime secrets | Production only | + +### Production + +| Aspect | Implementation | +|--------|----------------| +| Secrets storage | Encrypted with GCP KMS, stored in infrastructure config | +| CI/CD access | OIDC workload identity federation (no long-lived keys in repos) | +| 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..b4cd96a --- /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-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..67a2c67 --- /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 registry | Stored in release metadata | +| 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..d6c6179 --- /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-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..d88e561 --- /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-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..d4ccb75 --- /dev/null +++ b/security/threat-model/architecture.md @@ -0,0 +1,320 @@ +# 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(s3, "Object Storage", "S3", "Tarballs, registry files, documentation") + + 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, s3, "Registry files", "/names, /versions, /packages/*") + Rel(fastly, s3, "Tarballs", "/tarballs/*") + Rel(fastly, hexpm_web, "API requests", "/api/*") + Rel(fastly, hexdocs, "Documentation", "HTTPS") + + Rel(hexpm_web, postgres, "Reads/writes", "PostgreSQL") + Rel(hexpm_web, s3, "Stores packages", "S3 API") + Rel(hexpm_web, registry_worker, "Triggers rebuild") + Rel(hexpm_web, notification_worker, "Queues notifications") + + Rel(hexdocs, s3, "Reads docs", "S3 API") + Rel(preview, hexpm_web, "Fetches package data", "Internal API") + Rel(diff, hexpm_web, "Fetches package versions", "Internal API") + + Rel(registry_worker, s3, "Writes registry", "S3 API") + Rel(notification_worker, email, "Sends email", "SMTP") + + 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", "Primary + Replica", "Application data") + ContainerDb(s3_prod, "S3 Bucket", "Object Storage", "Tarballs, registry, docs") + } + } + + 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(hexdocs_prod, s3_prod, "S3 API") + Rel(diff_prod, edge, "Fetch packages", "repo.hex.pm") + Rel(preview_prod, s3_prod, "S3 events", "Tarball notifications") + + 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 + S3 | Content delivery and storage | Artifact integrity, signed registry | +| 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, "S3 Storage", "Package artifacts") + 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-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 (OAuth + 2FA) + 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-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..a608f3c --- /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-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..ef03d52 --- /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) are secure | Signature and checksum schemes 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..29e6ef4 --- /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. OAuth tokens have read-only permissions by default; write operations require 2FA. API keys can still be used directly, especially for CI environments. 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 /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-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 | `~/.cache/rebar3/hex/hexpm/registry/` | Registry protobuf files | +| 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-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. OAuth tokens have read-only permissions by default; write operations require 2FA. API keys can be used via the `HEXPM_API_KEY` environment variable for CI environments. 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` | OAuth refresh token (encrypted with user passphrase) | +| 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 /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-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 /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 | +|----------|--------|-------------| +| `/oauth/device_authorization` | POST | Initiate device flow | +| `/oauth/token` | POST | Exchange codes for tokens / refresh tokens | +| `/oauth/revoke` | POST | Revoke tokens | + +### Token Properties + +| Property | Value | +|----------|-------| +| Access token lifetime | Short-lived (configurable) | +| Refresh token lifetime | Long-lived | +| Default scope | `api` (includes write permissions) | +| 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 /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 /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: 400 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 /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..977cedf --- /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-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 | We submit to OSV but don't yet consume it in hex.pm or clients | +| 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 | Planned | Advisories displayed on package pages | +| 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 | Advisories, CNA, audit tools | Implemented | Strong coverage | +| T9: Unmaintained packages | Metadata, retirement status | Partial | Succession process informal | +| T10: Build pipeline compromise | (Planned: Trusted Publishing) | Planned | Gap - highest priority | \ No newline at end of file diff --git a/security/threat-model/overview.md b/security/threat-model/overview.md new file mode 100644 index 0000000..c9a73d2 --- /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 Package Managers](https://www.enisa.europa.eu/) | +| 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..b15c947 --- /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 [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 | + From 98ca7ac58a74890a701fb3fee5cf0004eb006860 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eric=20Meadows-J=C3=B6nsson?= Date: Sun, 10 May 2026 22:15:25 +0200 Subject: [PATCH 2/2] Minor fixes and suggested improvements --- security/operations/access-control.md | 3 +- security/sdlc/build.md | 10 +++-- security/sdlc/process.md | 2 +- security/sdlc/risk-register.md | 12 +++--- security/sdlc/runtime.md | 6 ++- security/supply-chain/overview.md | 2 +- security/supply-chain/provenance.md | 2 +- security/supply-chain/signing.md | 2 +- security/supply-chain/verification.md | 2 +- security/threat-model/architecture.md | 62 ++++++++++++++++++--------- security/threat-model/assets.md | 2 +- security/threat-model/assumptions.md | 2 +- security/threat-model/client-flows.md | 36 ++++++++-------- security/threat-model/mitigations.md | 10 ++--- security/threat-model/overview.md | 2 +- security/threat-model/threats.md | 2 +- 16 files changed, 93 insertions(+), 64 deletions(-) diff --git a/security/operations/access-control.md b/security/operations/access-control.md index 86dcf3c..81f3974 100644 --- a/security/operations/access-control.md +++ b/security/operations/access-control.md @@ -37,7 +37,8 @@ Access is logged via GCP Cloud Logging and GKE audit logs. ### Cloud Provider Access -- CI/CD uses OIDC workload identity federation (no long-lived service account keys) +- 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 diff --git a/security/sdlc/build.md b/security/sdlc/build.md index f7ac959..5efe567 100644 --- a/security/sdlc/build.md +++ b/security/sdlc/build.md @@ -26,7 +26,7 @@ This document describes secure build practices for Hex registry infrastructure. |----------|----------------| | Checksums | SHA-256 in signed registry | | Immutability | Cannot modify after grace period | -| Registry signing | RSA-SHA512 signatures | +| Registry signing | RSA-PKCS1-SHA512 signatures | ## Dependencies @@ -88,11 +88,15 @@ These projects must only use OTP standard library functions or vendor library co ### 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 | OAuth2 access token | -| No long-lived secrets | Short-lived tokens from 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 diff --git a/security/sdlc/process.md b/security/sdlc/process.md index fc1dcc8..ef36dd2 100644 --- a/security/sdlc/process.md +++ b/security/sdlc/process.md @@ -78,7 +78,7 @@ The Hex client is integration tested against the hexpm registry. | Scanner | Trigger | Scope | |---------|---------|-------| | CodeQL | Push/PR to main, weekly | GitHub Actions | -| Zizmor | Push/PR to main | Workflow security | +| Zizmor | Push/PR to main, weekly | Workflow security | ### Vulnerability Sources diff --git a/security/sdlc/risk-register.md b/security/sdlc/risk-register.md index 061605c..85691d6 100644 --- a/security/sdlc/risk-register.md +++ b/security/sdlc/risk-register.md @@ -4,12 +4,12 @@ This document tracks accepted security risks and their mitigations for Hex regis ## Active Risks -| ID | Risk | Severity | Status | Mitigation | Reference | -|----|------|----------|--------|------------|-----------| -| R-001 | Basic Authentication maintained for backward compatibility | Medium | Mitigating | OAuth2 migration planned; rate limiting in place | Security Audit 2026 | -| R-002 | Documentation hosted as full websites (HTML/JS) | Low | Accepted | Malicious content removed upon report | Security Audit 2026 | -| R-003 | User enumeration via API | Low | Accepted | Users are public for package publication; profile info is user-provided | Security Audit 2026 | -| R-004 | No WAF | Low | Accepted | SQL injection prevented by Ecto; XSS prevented by CSP; little added value expected | Security Audit 2026 | +| 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 diff --git a/security/sdlc/runtime.md b/security/sdlc/runtime.md index 4417259..27ffb8c 100644 --- a/security/sdlc/runtime.md +++ b/security/sdlc/runtime.md @@ -27,7 +27,8 @@ environment. | Secret | Storage | Access | |--------|---------|--------| -| GCP service account | GitHub secrets | OIDC workload identity | +| 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 @@ -35,7 +36,8 @@ environment. | Aspect | Implementation | |--------|----------------| | Secrets storage | Encrypted with GCP KMS, stored in infrastructure config | -| CI/CD access | OIDC workload identity federation (no long-lived keys in repos) | +| 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 diff --git a/security/supply-chain/overview.md b/security/supply-chain/overview.md index b4cd96a..fede6ac 100644 --- a/security/supply-chain/overview.md +++ b/security/supply-chain/overview.md @@ -55,7 +55,7 @@ flowchart LR | Property | Description | Status | |----------|-------------|--------| -| Signed registry | Metadata signed with RSA-SHA512 | Implemented | +| 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 | diff --git a/security/supply-chain/provenance.md b/security/supply-chain/provenance.md index 67a2c67..5dec736 100644 --- a/security/supply-chain/provenance.md +++ b/security/supply-chain/provenance.md @@ -18,7 +18,7 @@ Provenance answers: | Attribute | Tracked | Verifiable | Notes | |-----------|---------|------------|-------| | Publishing user | Yes | Via audit log | Account that initiated publish | -| Publish timestamp | Yes | Via registry | Stored in release metadata | +| 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 | diff --git a/security/supply-chain/signing.md b/security/supply-chain/signing.md index d6c6179..b52346a 100644 --- a/security/supply-chain/signing.md +++ b/security/supply-chain/signing.md @@ -46,7 +46,7 @@ sequenceDiagram CDN-->>Client: Compressed data Client->>Client: Decompress Client->>Client: Parse Signed protobuf - Client->>Client: Verify RSA-SHA512 signature + Client->>Client: Verify RSA-PKCS1-SHA512 signature alt Signature valid Client->>Client: Parse inner payload Client->>Client: Verify repository field diff --git a/security/supply-chain/verification.md b/security/supply-chain/verification.md index d88e561..64933e2 100644 --- a/security/supply-chain/verification.md +++ b/security/supply-chain/verification.md @@ -31,7 +31,7 @@ All clients perform these steps: flowchart TD A[Fetch registry file] --> B[Decompress gzip] B --> C[Parse Signed protobuf] - C --> D{Verify RSA-SHA512
signature} + C --> D{Verify RSA-PKCS1-SHA512
signature} D -->|Valid| E[Parse inner payload] D -->|Invalid| F[ABORT - tampering detected] E --> G{Repository field
matches?} diff --git a/security/threat-model/architecture.md b/security/threat-model/architecture.md index d4ccb75..0eed36a 100644 --- a/security/threat-model/architecture.md +++ b/security/threat-model/architecture.md @@ -98,7 +98,10 @@ C4Container Container(diff, "diff.hex.pm", "Phoenix/Elixir", "Visual diff between package versions") ContainerDb(postgres, "PostgreSQL", "Database", "Users, packages, releases, API keys, organizations") - ContainerDb(s3, "Object Storage", "S3", "Tarballs, registry files, documentation") + 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") @@ -109,22 +112,29 @@ C4Container Rel(consumer, fastly, "Fetches packages", "HTTPS") Rel(maintainer, fastly, "Publishes packages", "HTTPS") - Rel(fastly, s3, "Registry files", "/names, /versions, /packages/*") - Rel(fastly, s3, "Tarballs", "/tarballs/*") + Rel(fastly, aws_s3, "Registry files", "/names, /versions, /packages/*") + Rel(fastly, aws_s3, "Tarballs", "/tarballs/*") Rel(fastly, hexpm_web, "API requests", "/api/*") - Rel(fastly, hexdocs, "Documentation", "HTTPS") + Rel(fastly, gcs, "Documentation, preview", "HTTPS") Rel(hexpm_web, postgres, "Reads/writes", "PostgreSQL") - Rel(hexpm_web, s3, "Stores packages", "S3 API") + Rel(hexpm_web, aws_s3, "Stores packages", "S3 API") Rel(hexpm_web, registry_worker, "Triggers rebuild") Rel(hexpm_web, notification_worker, "Queues notifications") - Rel(hexdocs, s3, "Reads docs", "S3 API") - Rel(preview, hexpm_web, "Fetches package data", "Internal API") - Rel(diff, hexpm_web, "Fetches package versions", "Internal API") + 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, s3, "Writes registry", "S3 API") - Rel(notification_worker, email, "Sends email", "SMTP") + Rel(registry_worker, aws_s3, "Writes registry", "S3 API") + Rel(notification_worker, email, "Sends email", "SendGrid HTTP API") UpdateLayoutConfig($c4ShapeInRow="4", $c4BoundaryInRow="1") ``` @@ -158,8 +168,11 @@ C4Deployment Container(diff_prod, "diff.hex.pm", "Phoenix/Elixir", "Diff viewer") } Deployment_Node(data_tier, "Data Tier", "") { - ContainerDb(pg_prod, "PostgreSQL", "Primary + Replica", "Application data") - ContainerDb(s3_prod, "S3 Bucket", "Object Storage", "Tarballs, registry, docs") + 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") } } @@ -177,9 +190,16 @@ C4Deployment Rel(hex_prod, pg_prod, "PostgreSQL") Rel(hex_prod, s3_prod, "S3 API") - Rel(hexdocs_prod, s3_prod, "S3 API") - Rel(diff_prod, edge, "Fetch packages", "repo.hex.pm") - Rel(preview_prod, s3_prod, "S3 events", "Tarball notifications") + 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") @@ -200,7 +220,8 @@ C4Deployment |-----------|-------------|---------------| | hex.pm API | Package registry API | Authentication, authorization, publishing | | hex.pm Web | Web interface | User management, 2FA, session handling | -| Fastly CDN + S3 | Content delivery and storage | Artifact integrity, signed registry | +| 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 | @@ -215,7 +236,8 @@ C4Context Boundary(trusted, "Trusted Zone") { System(hexpm, "hex.pm", "Main application") System(fastly, "Fastly CDN", "Edge delivery") - SystemDb(s3, "S3 Storage", "Package artifacts") + SystemDb(s3, "AWS S3", "Registry + tarballs") + SystemDb(gcs, "Google Cloud Storage", "Docs, diff cache, preview cache") SystemDb(pg, "PostgreSQL", "Application data") } @@ -265,7 +287,7 @@ C4Context | Path | Protocol | Format | Authentication | Integrity | |------|----------|--------|----------------|-----------| -| Client → Registry files | HTTPS | Protobuf + gzip | None (public) or API key (private) or OAuth2 (private) | RSA-SHA512 signatures | +| 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 | @@ -286,7 +308,7 @@ sequenceDiagram participant Worker as Registry Builder participant CDN as Fastly CDN - Client->>API: Publish package (OAuth + 2FA) + 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 @@ -310,7 +332,7 @@ sequenceDiagram CDN->>S3: Cache miss (if needed) S3-->>CDN: Registry files CDN-->>Client: Signed registry - Client->>Client: Verify RSA-SHA512 signature + Client->>Client: Verify RSA-PKCS1-SHA512 signature Client->>CDN: Fetch package tarball CDN->>S3: Cache miss (if needed) S3-->>CDN: Tarball diff --git a/security/threat-model/assets.md b/security/threat-model/assets.md index a608f3c..334c1d8 100644 --- a/security/threat-model/assets.md +++ b/security/threat-model/assets.md @@ -24,7 +24,7 @@ Signed protobuf files containing package versions, dependencies, and checksums. |-----------|-------------| | Location | S3 storage (protobuf files), served via CDN | | Impact if compromised | Dependency confusion, version manipulation | -| Protection | RSA-SHA512 signatures, repository field verification | +| Protection | RSA-PKCS1-SHA512 signatures, repository field verification | ### Registry Signing Key diff --git a/security/threat-model/assumptions.md b/security/threat-model/assumptions.md index ef03d52..705989d 100644 --- a/security/threat-model/assumptions.md +++ b/security/threat-model/assumptions.md @@ -28,7 +28,7 @@ For controls that address threats under these assumptions, see [Mitigations](mit |------------|-------------| | 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) are secure | Signature and checksum schemes depend on this | +| Cryptographic primitives (RSA, SHA-256, SHA-512) are secure | RSA-PKCS1-SHA512 signatures and SHA-256 checksums depend on this | ### About Clients diff --git a/security/threat-model/client-flows.md b/security/threat-model/client-flows.md index 29e6ef4..92db614 100644 --- a/security/threat-model/client-flows.md +++ b/security/threat-model/client-flows.md @@ -50,7 +50,7 @@ Command: `mix deps.get` ### Authentication -Mix/Hex uses OAuth2 Device Authorization Grant ([RFC 8628](https://datatracker.ietf.org/doc/html/rfc8628)) for interactive authentication. OAuth tokens have read-only permissions by default; write operations require 2FA. API keys can still be used directly, especially for CI environments. See [OAuth2 Device Authorization Grant](#6-oauth2-device-authorization-grant) for details. +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 @@ -90,7 +90,7 @@ sequenceDiagram alt Has OAuth Token Hex->>Hex: Check token expiry (expires within 5 min?) opt Token Expired or Expiring Soon - Hex->>API: POST /oauth/token
grant_type=refresh_token + Hex->>API: POST /api/oauth/token
grant_type=refresh_token API-->>Hex: New access_token + refresh_token Hex->>Cache: Update hex.config end @@ -115,7 +115,7 @@ sequenceDiagram S3-->>CDN: Signed protobuf (gzip) CDN-->>HexCore: 200 OK + ETag - Note over HexCore: Verify RSA-SHA512 signature + Note over HexCore: Verify RSA-PKCS1-SHA512 signature HexCore->>HexCore: gunzip → decode Signed protobuf HexCore->>HexCore: verify(payload, signature, public_key) @@ -202,7 +202,7 @@ Rebar3 uses basic authentication to generate API keys. Unlike Mix/Hex and Gleam, | Cache | Path | Contents | |-------|------|----------| -| Registry | `~/.cache/rebar3/hex/hexpm/registry/` | Registry protobuf files | +| 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 | @@ -230,7 +230,7 @@ sequenceDiagram CDN-->>HexCore: Versions data Note over HexCore: Verify signature - HexCore->>HexCore: gunzip → verify RSA-SHA512 + HexCore->>HexCore: gunzip → verify RSA-PKCS1-SHA512 HexCore-->>Rebar: Package versions list loop For each dependency @@ -283,14 +283,14 @@ Command: `gleam build` ### Authentication -Gleam uses OAuth2 Device Authorization Grant ([RFC 8628](https://datatracker.ietf.org/doc/html/rfc8628)) for interactive authentication. OAuth tokens have read-only permissions by default; write operations require 2FA. API keys can be used via the `HEXPM_API_KEY` environment variable for CI environments. See [OAuth2 Device Authorization Grant](#6-oauth2-device-authorization-grant) for details. +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` | OAuth refresh token (encrypted with user passphrase) | +| 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 | @@ -404,7 +404,7 @@ sequenceDiagram alt Has OAuth Token Client->>Client: Check token expiry opt Token Expired - Client->>API: POST /oauth/token (refresh_token grant) + Client->>API: POST /api/oauth/token (refresh_token grant) API-->>Client: New access_token + refresh_token end Client->>Dev: Prompt for 2FA code @@ -438,7 +438,7 @@ sequenceDiagram Worker->>Worker: Rebuild /names protobuf Worker->>Worker: Rebuild /versions protobuf Worker->>Worker: Rebuild /packages/{name} protobuf - Worker->>Worker: Sign all with RSA-SHA512 + Worker->>Worker: Sign all with RSA-PKCS1-SHA512 Worker->>Worker: Gzip compress Worker->>S3: Upload registry files @@ -494,7 +494,7 @@ sequenceDiagram Cache-->>Client: auth_key alt OAuth exchange enabled (default for hex.pm) - Client->>API: POST /oauth/token
grant_type=client_credentials
Authorization: {auth_key} + 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 @@ -563,9 +563,9 @@ Mix/Hex and Gleam use [RFC 8628 OAuth2 Device Authorization Grant](https://datat | Endpoint | Method | Description | |----------|--------|-------------| -| `/oauth/device_authorization` | POST | Initiate device flow | -| `/oauth/token` | POST | Exchange codes for tokens / refresh tokens | -| `/oauth/revoke` | POST | Revoke tokens | +| `/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 @@ -573,7 +573,7 @@ Mix/Hex and Gleam use [RFC 8628 OAuth2 Device Authorization Grant](https://datat |----------|-------| | Access token lifetime | Short-lived (configurable) | | Refresh token lifetime | Long-lived | -| Default scope | `api` (includes write permissions) | +| 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 @@ -589,7 +589,7 @@ sequenceDiagram Dev->>Client: mix hex.user auth / gleam hex authenticate Note over Client,API: Step 1: Device Authorization Request - Client->>API: POST /oauth/device_authorization
client_id={client_id}
name={client_name} + 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 @@ -611,7 +611,7 @@ sequenceDiagram Note over Client,API: Step 4: Token Polling loop Poll until authorized or expired - Client->>API: POST /oauth/token
grant_type=urn:ietf:params:oauth:grant-type:device_code
device_code={device_code}
client_id={client_id} + 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 @@ -619,7 +619,7 @@ sequenceDiagram API-->>Client: 400 slow_down Client->>Client: Increase polling interval else Access Denied - API-->>Client: 400 access_denied + API-->>Client: 403 access_denied Client-->>Dev: ❌ Authorization denied else Expired API-->>Client: 400 expired_token @@ -644,7 +644,7 @@ sequenceDiagram Client->>Client: Check access_token expiry alt Token expires within 5 minutes - Client->>API: POST /oauth/token
grant_type=refresh_token
refresh_token={refresh_token}
client_id={client_id} + 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 diff --git a/security/threat-model/mitigations.md b/security/threat-model/mitigations.md index 977cedf..c168c6b 100644 --- a/security/threat-model/mitigations.md +++ b/security/threat-model/mitigations.md @@ -86,7 +86,7 @@ Addresses: [T3](threats.md#t3-package-tampering) | Control | Status | Description | |---------|--------|-------------| -| RSA-SHA512 signatures | Implemented | All registry files are signed | +| 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) | @@ -238,7 +238,7 @@ Addresses: [T8](threats.md#t8-vulnerable-dependencies-transitive) | Control | Status | Description | |---------|--------|-------------| -| Advisory database integration | Partial | We submit to OSV but don't yet consume it in hex.pm or clients | +| 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). @@ -250,7 +250,7 @@ See [SDLC - Secure Process](../sdlc/process.md#vulnerability-handling). | `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 | Planned | Advisories displayed on package pages | +| 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 | @@ -292,6 +292,6 @@ Addresses: [T9](threats.md#t9-unmaintainedabandoned-packages) | 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 | Advisories, CNA, audit tools | 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 | \ No newline at end of file +| 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 index c9a73d2..997f88e 100644 --- a/security/threat-model/overview.md +++ b/security/threat-model/overview.md @@ -26,7 +26,7 @@ This threat model draws from established supply chain security frameworks: | Framework | Focus | Reference | |-----------|-------|-----------| -| ENISA | Package manager security risks | [Technical Advisory for Package Managers](https://www.enisa.europa.eu/) | +| 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) | diff --git a/security/threat-model/threats.md b/security/threat-model/threats.md index b15c947..121eae6 100644 --- a/security/threat-model/threats.md +++ b/security/threat-model/threats.md @@ -425,7 +425,7 @@ An attacker compromises the build or CI/CD pipeline of package maintainers, inje ### Related Controls -See [Supply Chain - Provenance](../supply-chain/provenance.md). +See [Build Provenance](./mitigations.md#build-provenance) under Supply Chain Integrity and [Supply Chain - Provenance](../supply-chain/provenance.md). ## Framework Cross-Reference