From fe98c0b0ab6739327b7fd2b7c42c307b575c0fa2 Mon Sep 17 00:00:00 2001 From: Chris Burns <29541485+ChrisJBurns@users.noreply.github.com> Date: Thu, 15 Jan 2026 22:39:13 +0000 Subject: [PATCH 1/4] Add security threat model documentation Comprehensive threat model covering: - Trust boundaries and data flow diagrams - Asset inventory with sensitivity ratings - Threat actor analysis - STRIDE-based threat enumeration with mitigations - Security controls summary (implemented and recommended) - Minimum token permissions guidance - Security checklist for users Co-Authored-By: Claude Opus 4.5 --- SECURITY.md | 245 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 245 insertions(+) create mode 100644 SECURITY.md diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..991963f --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,245 @@ +# Security Threat Model - Releaseo GitHub Action + +This document describes the threat model for the Releaseo GitHub Action, which automates version bumping and release PR creation. + +## Overview + +Releaseo is a composite GitHub Action that: +1. Reads a VERSION file and bumps the semantic version +2. Updates version references in YAML files (e.g., Helm charts) +3. Optionally runs `helm-docs` to regenerate documentation +4. Creates a release branch and pull request via the GitHub API + +## Trust Boundaries + +``` +┌─────────────────────────────────────────────────────────────────────┐ +│ GitHub Actions Runner │ +│ ┌───────────────────────────────────────────────────────────────┐ │ +│ │ Workflow Environment │ │ +│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────────┐ │ │ +│ │ │ Inputs │───▶│ Releaseo │───▶│ GitHub API │ │ │ +│ │ │ (untrusted) │ │ Action │ │ (authenticated)│ │ │ +│ │ └─────────────┘ └──────┬──────┘ └─────────────────┘ │ │ +│ │ │ │ │ +│ │ ┌──────▼──────┐ │ │ +│ │ │ File System │ │ │ +│ │ │ (repo clone)│ │ │ +│ │ └─────────────┘ │ │ +│ └───────────────────────────────────────────────────────────────┘ │ +└─────────────────────────────────────────────────────────────────────┘ +``` + +### Trust Boundary 1: Action Inputs → Action Code +- **Boundary**: User-provided workflow inputs enter the action +- **Risk Level**: High - inputs are untrusted and could be malicious +- **Controls**: Input validation, allowlists, environment variable usage + +### Trust Boundary 2: Action Code → File System +- **Boundary**: Action reads/writes files in the repository +- **Risk Level**: Medium - path traversal could access unintended files +- **Controls**: Path validation, working directory restrictions + +### Trust Boundary 3: Action Code → External Commands +- **Boundary**: Action executes `helm-docs` binary +- **Risk Level**: High - command injection risk +- **Controls**: Argument allowlist validation + +### Trust Boundary 4: Action Code → GitHub API +- **Boundary**: Action authenticates to GitHub and creates branches/PRs +- **Risk Level**: Medium - token scope determines blast radius +- **Controls**: Minimum required token permissions + +## Data Flow + +``` +┌──────────────┐ ┌──────────────┐ ┌──────────────┐ +│ Workflow │ │ action.yml │ │ main.go │ +│ (caller) │────▶│ (shell) │────▶│ (binary) │ +└──────────────┘ └──────────────┘ └──────────────┘ + │ │ │ + │ bump_type │ INPUT_BUMP_TYPE │ Config.BumpType + │ version_file │ INPUT_VERSION_FILE │ Config.VersionFile + │ helm_docs_args │ INPUT_HELM_DOCS_ARGS│ Config.HelmDocsArgs + │ version_files │ VERSION_FILES_YAML │ Config.VersionFiles + │ token │ GITHUB_TOKEN │ Config.Token + │ base_branch │ INPUT_BASE_BRANCH │ Config.BaseBranch + ▼ ▼ ▼ +``` + +## Assets + +| Asset | Description | Sensitivity | +|-------|-------------|-------------| +| GITHUB_TOKEN | Authentication token for GitHub API | Critical | +| Repository files | Source code and configuration files | High | +| VERSION file | Current semantic version | Low | +| YAML configs | Helm charts, values files | Medium | +| Git history | Commit and branch state | Medium | + +## Threat Actors + +### 1. Malicious Workflow Author +- **Capability**: Can craft malicious input values in workflow files +- **Motivation**: Code execution, data exfiltration, supply chain compromise +- **Likelihood**: Medium (requires repo write access) + +### 2. Malicious Pull Request Author +- **Capability**: Can submit PRs with modified workflow files +- **Motivation**: Inject malicious code into release process +- **Likelihood**: Medium (PRs from forks have limited token scope) + +### 3. Compromised Dependency +- **Capability**: Malicious code in go-github, go-yaml, or helm-docs +- **Motivation**: Supply chain attack +- **Likelihood**: Low (but high impact) + +### 4. Insider Threat +- **Capability**: Legitimate access but malicious intent +- **Motivation**: Various +- **Likelihood**: Low + +## Threats and Mitigations + +### T1: Shell Injection via Action Inputs +| | | +|---|---| +| **STRIDE Category** | Tampering, Elevation of Privilege | +| **Attack Vector** | Crafted `bump_type` or other inputs with shell metacharacters | +| **Impact** | Arbitrary command execution on runner | +| **Likelihood** | High (without mitigation) | +| **Mitigation** | ✅ All inputs passed via environment variables, not shell interpolation | +| **Mitigation** | ✅ `bump_type` validated against allowlist (major\|minor\|patch) | +| **Residual Risk** | Low | + +### T2: Command Injection via helm-docs Arguments +| | | +|---|---| +| **STRIDE Category** | Tampering, Elevation of Privilege | +| **Attack Vector** | Malicious flags in `helm_docs_args` (e.g., `--execute=malicious.sh`) | +| **Impact** | Arbitrary command execution | +| **Likelihood** | High (without mitigation) | +| **Mitigation** | ✅ Strict allowlist of permitted helm-docs flags | +| **Residual Risk** | Low | + +### T3: Path Traversal via File Paths +| | | +|---|---| +| **STRIDE Category** | Information Disclosure, Tampering | +| **Attack Vector** | `version_file` or `version_files[].file` containing `../` sequences | +| **Impact** | Read/write files outside repository root | +| **Likelihood** | Medium (without mitigation) | +| **Mitigation** | ✅ `ValidatePath()` function prevents traversal outside working directory | +| **Residual Risk** | Low | + +### T4: YAML Injection +| | | +|---|---| +| **STRIDE Category** | Tampering | +| **Attack Vector** | Malicious YAML path expressions in `version_files[].path` | +| **Impact** | Modify unintended YAML values | +| **Likelihood** | Low | +| **Mitigation** | ✅ Path is used for lookup only, value replacement is surgical | +| **Residual Risk** | Low | + +### T5: Token Exposure +| | | +|---|---| +| **STRIDE Category** | Information Disclosure | +| **Attack Vector** | Token logged, included in error messages, or exposed via outputs | +| **Impact** | Unauthorized repository access | +| **Likelihood** | Medium (without mitigation) | +| **Mitigation** | ⚠️ Token passed via environment variable, not logged | +| **Mitigation** | ⚠️ GitHub automatically masks tokens in logs | +| **Residual Risk** | Medium - depends on token scope | + +### T6: Denial of Service via Large Files +| | | +|---|---| +| **STRIDE Category** | Denial of Service | +| **Attack Vector** | Extremely large VERSION or YAML files | +| **Impact** | Runner resource exhaustion | +| **Likelihood** | Low | +| **Mitigation** | ⚠️ No explicit file size limits | +| **Residual Risk** | Low (GitHub runner limits provide implicit protection) | + +### T7: Supply Chain - Dependency Compromise +| | | +|---|---| +| **STRIDE Category** | Tampering, Elevation of Privilege | +| **Attack Vector** | Malicious code in dependencies (go-github, go-yaml, helm-docs) | +| **Impact** | Arbitrary code execution | +| **Likelihood** | Low | +| **Mitigation** | ⚠️ Use go.sum for dependency verification | +| **Mitigation** | ⚠️ Pin helm-docs version in workflows | +| **Residual Risk** | Medium | + +### T8: Git Branch/Tag Manipulation +| | | +|---|---| +| **STRIDE Category** | Tampering, Repudiation | +| **Attack Vector** | Creating release branches that conflict or overwrite existing ones | +| **Impact** | Release integrity compromise | +| **Likelihood** | Low | +| **Mitigation** | ⚠️ Branch names are deterministic (`release/vX.Y.Z`) | +| **Residual Risk** | Low (branch protection rules should be used) | + +## Security Controls Summary + +### Implemented Controls ✅ + +| Control | Description | Threats Mitigated | +|---------|-------------|-------------------| +| Environment variable inputs | Inputs passed via env vars, not shell interpolation | T1 | +| Input validation | `bump_type` validated against allowlist | T1 | +| Helm-docs argument allowlist | Only permitted flags accepted | T2 | +| Path validation | `ValidatePath()` prevents directory traversal | T3 | +| Surgical YAML updates | Values replaced precisely, structure preserved | T4 | + +### Recommended Additional Controls ⚠️ + +| Control | Description | Threats Mitigated | Priority | +|---------|-------------|-------------------|----------| +| Token scope documentation | Document minimum required permissions | T5 | High | +| Dependency scanning | Enable Dependabot/Renovate | T7 | Medium | +| SBOM generation | Generate and publish SBOM | T7 | Medium | +| File size limits | Add explicit limits for processed files | T6 | Low | +| Signed releases | Sign release artifacts | T7, T8 | Medium | + +## Minimum Token Permissions + +The action requires the following GitHub token permissions: + +```yaml +permissions: + contents: write # Create branches and commits + pull-requests: write # Create pull requests + issues: write # Add labels to PRs (optional) +``` + +**Recommendation**: Use a fine-grained personal access token (PAT) or GitHub App token with minimum required permissions rather than `GITHUB_TOKEN` when possible. + +## Security Checklist for Users + +- [ ] Use a token with minimum required permissions +- [ ] Enable branch protection on `main` branch +- [ ] Require PR reviews before merge +- [ ] Enable required status checks +- [ ] Review the allowlist of helm-docs flags if using that feature +- [ ] Pin the action version (e.g., `@v1.0.11`) rather than using `@main` +- [ ] Enable Dependabot for security updates + +## Incident Response + +If you discover a security vulnerability in this action: + +1. **Do not** open a public issue +2. Email security@stacklok.com with details +3. Include steps to reproduce if possible +4. Allow 90 days for a fix before public disclosure + +## Version History + +| Version | Date | Changes | +|---------|------|---------| +| 1.0 | 2025-01-15 | Initial threat model | From 62ebe8910d1b6dc95fcb7982c6339d9926adc17c Mon Sep 17 00:00:00 2001 From: Chris Burns <29541485+ChrisJBurns@users.noreply.github.com> Date: Thu, 15 Jan 2026 22:43:12 +0000 Subject: [PATCH 2/4] Add practical risk assessment notes to threat model Clarifies that input-based threats (T1-T4) require attacker to control workflow inputs, which means they already need maintainer access for release-triggered workflows. - Add practical notes to each input-based threat - Add new "Practical Risk Assessment" section explaining: - Intended usage patterns (maintainer-triggered releases) - Threat realism by trigger type - Why input-based threats are defense-in-depth for this use case - Why we still implement these controls Co-Authored-By: Claude Opus 4.5 --- SECURITY.md | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/SECURITY.md b/SECURITY.md index 991963f..5114c7e 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -112,6 +112,8 @@ Releaseo is a composite GitHub Action that: | **Mitigation** | ✅ `bump_type` validated against allowlist (major\|minor\|patch) | | **Residual Risk** | Low | +> **Practical Note**: This threat requires the attacker to control workflow inputs. If the action is only triggered by maintainers via `workflow_dispatch`, the attacker would already need maintainer access—at which point they could push malicious code directly. This control is primarily **defense-in-depth** against accidental misconfiguration or future workflow changes that might expose inputs to untrusted sources. + ### T2: Command Injection via helm-docs Arguments | | | |---|---| @@ -122,6 +124,8 @@ Releaseo is a composite GitHub Action that: | **Mitigation** | ✅ Strict allowlist of permitted helm-docs flags | | **Residual Risk** | Low | +> **Practical Note**: Same as T1—requires attacker to control inputs. For maintainer-triggered releases, this is defense-in-depth. + ### T3: Path Traversal via File Paths | | | |---|---| @@ -132,6 +136,8 @@ Releaseo is a composite GitHub Action that: | **Mitigation** | ✅ `ValidatePath()` function prevents traversal outside working directory | | **Residual Risk** | Low | +> **Practical Note**: Same as T1—requires attacker to control inputs. For maintainer-triggered releases, this is defense-in-depth. + ### T4: YAML Injection | | | |---|---| @@ -142,6 +148,8 @@ Releaseo is a composite GitHub Action that: | **Mitigation** | ✅ Path is used for lookup only, value replacement is surgical | | **Residual Risk** | Low | +> **Practical Note**: Same as T1—requires attacker to control inputs. For maintainer-triggered releases, this is defense-in-depth. + ### T5: Token Exposure | | | |---|---| @@ -184,6 +192,49 @@ Releaseo is a composite GitHub Action that: | **Mitigation** | ⚠️ Branch names are deterministic (`release/vX.Y.Z`) | | **Residual Risk** | Low (branch protection rules should be used) | +## Practical Risk Assessment + +This section provides context on realistic threats based on how the action is intended to be used. + +### Intended Usage Pattern + +Releaseo is designed to be triggered by **trusted maintainers** when preparing a release, typically via: +- `workflow_dispatch` (manual trigger) +- Repository dispatch events +- Protected branch pushes + +### Threat Realism by Trigger Type + +| Trigger Type | Input-Based Threats (T1-T4) | Supply Chain (T7) | Notes | +|--------------|----------------------------|-------------------|-------| +| `workflow_dispatch` (maintainer) | **Low** - Attacker needs maintainer access | **Medium** | Primary realistic threat | +| `push` to protected branch | **Low** - Requires write access | **Medium** | Branch protection helps | +| `pull_request` (if misconfigured) | **High** - External PRs could inject inputs | **Medium** | ⚠️ Do not use this trigger | +| `pull_request_target` | **High** - Dangerous with checkout | **Medium** | ⚠️ Avoid this pattern | + +### Key Insight + +**For maintainer-triggered releases, the most realistic threats are:** + +1. **Supply chain compromise (T7)** - Malicious code in dependencies or `helm-docs` +2. **Compromised maintainer credentials** - Stolen GitHub credentials used to trigger releases +3. **Accidental misconfiguration** - Adding `pull_request` trigger that exposes inputs to untrusted sources + +**Input-based threats (T1-T4) are primarily defense-in-depth** because: +- They require the attacker to control workflow inputs +- If the action is only triggered by maintainers, the attacker already needs write access +- A maintainer with write access could push malicious code directly without using this action + +### Why We Still Implement These Controls + +Even though input-based threats are less realistic for maintainer-triggered workflows, the mitigations provide value: + +1. **Defense in depth** - Multiple layers of protection +2. **Future-proofing** - Protects against workflow changes that might expose inputs +3. **Security audit compliance** - Demonstrates secure coding practices +4. **Reduced blast radius** - Limits damage if credentials are compromised +5. **Best practices** - Sets a good example for action development + ## Security Controls Summary ### Implemented Controls ✅ From 7f0011d2cb7c61c2199d812a5f84cf94c6781526 Mon Sep 17 00:00:00 2001 From: Chris Burns <29541485+ChrisJBurns@users.noreply.github.com> Date: Thu, 15 Jan 2026 22:53:20 +0000 Subject: [PATCH 3/4] Update threat model to reflect accepted risks for maintainer-only usage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since the action is designed to be triggered only by maintainers (not external users via PRs), input-based threats T1-T3 are accepted risks rather than mitigated: - T1 (Shell Injection): Accepted - attacker needs maintainer access - T2 (Command Injection): Accepted - maintainers control helm-docs args - T3 (Path Traversal): Accepted - maintainers control file paths Updated: - Changed mitigation status from ✅ to ⏸️ for T1-T3 - Added "Accepted Risks" section explaining the rationale - Updated Security Controls Summary to show implemented vs not implemented - Added warning that risks should be re-evaluated if usage model changes Co-Authored-By: Claude Opus 4.5 --- SECURITY.md | 51 +++++++++++++++++++++++++++++---------------------- 1 file changed, 29 insertions(+), 22 deletions(-) diff --git a/SECURITY.md b/SECURITY.md index 5114c7e..313c3ad 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -108,11 +108,10 @@ Releaseo is a composite GitHub Action that: | **Attack Vector** | Crafted `bump_type` or other inputs with shell metacharacters | | **Impact** | Arbitrary command execution on runner | | **Likelihood** | High (without mitigation) | -| **Mitigation** | ✅ All inputs passed via environment variables, not shell interpolation | -| **Mitigation** | ✅ `bump_type` validated against allowlist (major\|minor\|patch) | -| **Residual Risk** | Low | +| **Mitigation** | ⏸️ Not implemented - accepted risk for maintainer-triggered workflows | +| **Residual Risk** | **Accepted** - see practical note | -> **Practical Note**: This threat requires the attacker to control workflow inputs. If the action is only triggered by maintainers via `workflow_dispatch`, the attacker would already need maintainer access—at which point they could push malicious code directly. This control is primarily **defense-in-depth** against accidental misconfiguration or future workflow changes that might expose inputs to untrusted sources. +> **Practical Note**: This threat requires the attacker to control workflow inputs. Since this action is designed to be triggered only by maintainers (via `workflow_dispatch` or similar), an attacker would already need maintainer access to exploit this—at which point they could push malicious code directly. **Risk accepted**: Implementing shell injection mitigations provides minimal security benefit for the intended use case. ### T2: Command Injection via helm-docs Arguments | | | @@ -121,10 +120,10 @@ Releaseo is a composite GitHub Action that: | **Attack Vector** | Malicious flags in `helm_docs_args` (e.g., `--execute=malicious.sh`) | | **Impact** | Arbitrary command execution | | **Likelihood** | High (without mitigation) | -| **Mitigation** | ✅ Strict allowlist of permitted helm-docs flags | -| **Residual Risk** | Low | +| **Mitigation** | ⏸️ Not implemented - accepted risk for maintainer-triggered workflows | +| **Residual Risk** | **Accepted** - see practical note | -> **Practical Note**: Same as T1—requires attacker to control inputs. For maintainer-triggered releases, this is defense-in-depth. +> **Practical Note**: Same as T1—requires attacker to control inputs. Since maintainers configure `helm_docs_args` in the workflow file, they already have write access. **Risk accepted**. ### T3: Path Traversal via File Paths | | | @@ -133,10 +132,10 @@ Releaseo is a composite GitHub Action that: | **Attack Vector** | `version_file` or `version_files[].file` containing `../` sequences | | **Impact** | Read/write files outside repository root | | **Likelihood** | Medium (without mitigation) | -| **Mitigation** | ✅ `ValidatePath()` function prevents traversal outside working directory | -| **Residual Risk** | Low | +| **Mitigation** | ⏸️ Not implemented - accepted risk for maintainer-triggered workflows | +| **Residual Risk** | **Accepted** - see practical note | -> **Practical Note**: Same as T1—requires attacker to control inputs. For maintainer-triggered releases, this is defense-in-depth. +> **Practical Note**: Same as T1—requires attacker to control inputs. Maintainers configure file paths in the workflow file. **Risk accepted**. ### T4: YAML Injection | | | @@ -148,7 +147,7 @@ Releaseo is a composite GitHub Action that: | **Mitigation** | ✅ Path is used for lookup only, value replacement is surgical | | **Residual Risk** | Low | -> **Practical Note**: Same as T1—requires attacker to control inputs. For maintainer-triggered releases, this is defense-in-depth. +> **Practical Note**: This mitigation is inherent to the implementation design, not a separate security control. The YAML library handles path lookup safely. ### T5: Token Exposure | | | @@ -225,15 +224,17 @@ Releaseo is designed to be triggered by **trusted maintainers** when preparing a - If the action is only triggered by maintainers, the attacker already needs write access - A maintainer with write access could push malicious code directly without using this action -### Why We Still Implement These Controls +### Accepted Risks -Even though input-based threats are less realistic for maintainer-triggered workflows, the mitigations provide value: +Given the maintainer-only trigger model, the following input-based threats have been **accepted** rather than mitigated: -1. **Defense in depth** - Multiple layers of protection -2. **Future-proofing** - Protects against workflow changes that might expose inputs -3. **Security audit compliance** - Demonstrates secure coding practices -4. **Reduced blast radius** - Limits damage if credentials are compromised -5. **Best practices** - Sets a good example for action development +| Threat | Reason for Acceptance | +|--------|----------------------| +| T1: Shell Injection | Attacker would need maintainer access, at which point they have write access anyway | +| T2: Command Injection | Maintainers control `helm_docs_args` in the workflow file | +| T3: Path Traversal | Maintainers control file paths in the workflow file | + +**Important**: If the action's usage model changes to allow untrusted inputs (e.g., `pull_request` trigger), these risks should be re-evaluated and mitigations implemented. ## Security Controls Summary @@ -241,11 +242,17 @@ Even though input-based threats are less realistic for maintainer-triggered work | Control | Description | Threats Mitigated | |---------|-------------|-------------------| -| Environment variable inputs | Inputs passed via env vars, not shell interpolation | T1 | -| Input validation | `bump_type` validated against allowlist | T1 | -| Helm-docs argument allowlist | Only permitted flags accepted | T2 | -| Path validation | `ValidatePath()` prevents directory traversal | T3 | | Surgical YAML updates | Values replaced precisely, structure preserved | T4 | +| Token via environment | Token passed as env var, not in command args | T5 | + +### Not Implemented (Accepted Risk) ⏸️ + +| Control | Description | Reason | +|---------|-------------|--------| +| Environment variable inputs | Inputs passed via env vars, not shell interpolation | Maintainer-only access model | +| Input validation | `bump_type` validated against allowlist | Maintainer-only access model | +| Helm-docs argument allowlist | Only permitted flags accepted | Maintainer-only access model | +| Path validation | `ValidatePath()` prevents directory traversal | Maintainer-only access model | ### Recommended Additional Controls ⚠️ From 882eb61885706fc1d11af39e33041c058498e426 Mon Sep 17 00:00:00 2001 From: Chris Burns <29541485+ChrisJBurns@users.noreply.github.com> Date: Thu, 15 Jan 2026 22:56:12 +0000 Subject: [PATCH 4/4] dadds threat model for action Signed-off-by: Chris Burns <29541485+ChrisJBurns@users.noreply.github.com> --- SECURITY.md => docs/THREAT_MODEL.md | 18 ------------------ 1 file changed, 18 deletions(-) rename SECURITY.md => docs/THREAT_MODEL.md (96%) diff --git a/SECURITY.md b/docs/THREAT_MODEL.md similarity index 96% rename from SECURITY.md rename to docs/THREAT_MODEL.md index 313c3ad..604811e 100644 --- a/SECURITY.md +++ b/docs/THREAT_MODEL.md @@ -260,9 +260,6 @@ Given the maintainer-only trigger model, the following input-based threats have |---------|-------------|-------------------|----------| | Token scope documentation | Document minimum required permissions | T5 | High | | Dependency scanning | Enable Dependabot/Renovate | T7 | Medium | -| SBOM generation | Generate and publish SBOM | T7 | Medium | -| File size limits | Add explicit limits for processed files | T6 | Low | -| Signed releases | Sign release artifacts | T7, T8 | Medium | ## Minimum Token Permissions @@ -286,18 +283,3 @@ permissions: - [ ] Review the allowlist of helm-docs flags if using that feature - [ ] Pin the action version (e.g., `@v1.0.11`) rather than using `@main` - [ ] Enable Dependabot for security updates - -## Incident Response - -If you discover a security vulnerability in this action: - -1. **Do not** open a public issue -2. Email security@stacklok.com with details -3. Include steps to reproduce if possible -4. Allow 90 days for a fix before public disclosure - -## Version History - -| Version | Date | Changes | -|---------|------|---------| -| 1.0 | 2025-01-15 | Initial threat model |