ADR-035: DevSecOps Implementation for Open Source¶
Status: ACCEPTED (v2) Date: 2025-12-28 Context: Security automation for OSS project with zero-cost contributor experience Depends On: ADR-033 (OSS Community Infrastructure) Author: @amiable-dev Council Review v1: 2025-12-28 (Reasoning Tier: openai/o1, google/gemini-3-pro-preview) Council Review v2: 2025-12-28 (High Tier: gpt-5.2, claude-opus-4.5, gemini-3-pro-preview, grok-4.1-fast)
Context¶
As LLM Council transitions to a public open source project (ADR-033), we need comprehensive security automation that:
- Protects users from vulnerabilities in dependencies and code
- Maintains zero cost for OSS contributors (no paid tool requirements)
- Minimizes friction in the contribution workflow
- Provides visibility into security posture for evaluators
Current State¶
Existing security measures:
- .github/workflows/ci.yml - Basic linting and tests
- SECURITY.md - Vulnerability reporting process (ADR-033)
- Manual dependency updates
Missing security automation: - Dependency vulnerability scanning - Static Application Security Testing (SAST) - Secret detection in commits - Container image scanning (for future Docker distribution) - Software Bill of Materials (SBOM) generation - Dynamic Application Security Testing (DAST) for HTTP API
Tool Landscape¶
The team has experience with enterprise security tools:
| Tool | Category | OSS-Free Tier | Notes |
|---|---|---|---|
| Snyk | SCA, SAST, Container | Yes (limited) | 200 tests/month on free tier |
| SonarCloud | SAST, Code Quality | Yes (public repos) | Free for public OSS |
| Aqua Trivy | Container, SCA | Yes (fully free) | Apache 2.0, CLI-based |
| Bright (NeuraLegion) | DAST | Limited free | Enterprise-focused |
| GitHub CodeQL | SAST | Yes (public repos) | Native GitHub integration |
| GitHub Dependabot | SCA | Yes (free) | Native, automatic PRs |
| GitHub Secret Scanning | Secrets | Yes (public repos) | Native, partner alerts |
| Gitleaks | Secrets | Yes (fully free) | Pre-commit hook friendly |
| Semgrep | SAST | Yes (community rules) | Fast, extensible |
| StackHawk | DAST | Limited free | Developer-friendly DAST |
Design Principles¶
- GitHub-Native First: Prefer GitHub's built-in security features
- Defense in Depth: Multiple overlapping tools catch different issues
- Shift Left: Catch issues in PRs before merge, not after release
- Non-Blocking by Default: Security findings are advisory in PRs, blocking only for critical/high severity
- Zero Contributor Cost: No paid accounts or API keys required to contribute
- Transparent Security: Public security posture (badges, scorecards)
- Fork-Aware Design: PR checks must work without secrets (forks don't have access to repo secrets)
Decision¶
Implement a layered DevSecOps pipeline using free-for-OSS tools, prioritizing GitHub-native features supplemented by best-in-class open source scanners.
Architecture: Security Layers¶
┌─────────────────────────────────────────────────────────────────┐
│ Layer 1: Pre-Commit │
│ Developer workstation (optional but recommended) │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Gitleaks │ │ Ruff │ │ Semgrep │ │
│ │ (secrets) │ │ (lint) │ │ (SAST) │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ Layer 2: Pull Request │
│ GitHub Actions (runs on every PR - fork-compatible) │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ CodeQL │ │ Dependabot │ │ Dep Review │ │
│ │ (SAST) │ │ (SCA) │ │ (license) │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ Semgrep │ │ Gitleaks │ │
│ │ (SAST+LLM) │ │ (secrets) │ │
│ └──────────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ Layer 3: Main Branch │
│ GitHub Actions (runs on merge to master) │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ SonarCloud │ │ Snyk │ │ Trivy │ │
│ │ (full scan) │ │ (monitor) │ │ (SCA) │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ ┌──────────────┐ │
│ │ SBOM Gen │ │
│ │ (CycloneDX) │ │
│ └──────────────┘ │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ Layer 4: Release │
│ GitHub Actions (runs on tag/release) │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Trivy │ │ Cosign │ │ SBOM │ │
│ │ (container) │ │ (signing) │ │ (attach) │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ Layer 5: Runtime (Future) │
│ For HTTP API deployment (Council Cloud) │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ StackHawk │ │ Runtime │ │
│ │ (DAST) │ │ Monitoring │ │
│ └──────────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────────────────┘
Tool Selection Rationale¶
1. Software Composition Analysis (SCA)¶
Primary: GitHub Dependabot (Native) - Automatic PRs for vulnerable dependencies - Zero configuration for public repos - Integrated security advisories
Secondary: Trivy (Apache 2.0) - Comprehensive vulnerability database (NVD, GitHub Advisory, etc.) - Scans Python dependencies, containers, IaC - Fast CI execution (~30s for Python project) - No API keys required
Monitoring: Snyk (Free tier)
- Continuous monitoring of master branch
- Remediation advice and fix PRs
- Free for OSS: 200 tests/month sufficient for our cadence
2. Static Application Security Testing (SAST)¶
Primary: GitHub CodeQL (Native) - Deep semantic analysis for Python - Queries for SQL injection, command injection, XSS - Native GitHub integration, appears in Security tab - Free for public repositories
Secondary: Semgrep (Community rules) - Fast pattern-based scanning (~10s) - Community rules for Python security - Custom rules for LLM-specific patterns (prompt injection) - OSS (LGPL-2.1), runs locally
Quality Gate: SonarCloud (Free for public repos) - Comprehensive code quality + security - Technical debt tracking - Quality gate blocking for critical issues - Free for public open source
3. Secret Detection¶
Primary: GitHub Secret Scanning (Native) - Partner program alerts (AWS, OpenAI, etc.) - Push protection (blocks commits with secrets) - Zero configuration
Secondary: Gitleaks (MIT License) - Pre-commit hook for local detection - CI validation for comprehensive patterns - Custom patterns for OpenRouter, etc. - Fully open source, no API keys
4. Container Security (Future)¶
Primary: Trivy (Apache 2.0) - Image vulnerability scanning - Dockerfile best practice checks - SBOM generation in CycloneDX/SPDX format - No API keys required
5. SBOM (Software Bill of Materials)¶
Tool: CycloneDX Python (Apache 2.0) - Generate SBOM from pyproject.toml/uv.lock - Attach to GitHub releases - Required for supply chain transparency
6. DAST (Future - HTTP API)¶
Deferred: DAST for HTTP API (/v1/council/run) will be implemented when Council Cloud launches. Options:
- StackHawk (free tier for OSS)
- OWASP ZAP (fully open source)
7. LLM-Specific Security (Council Recommendation)¶
Model Serialization Attacks: - If loading model weights (Pickle/PyTorch), use Modelscan or Picklescan - Standard SAST tools are blind to malicious serialization
Prompt Injection Defense: - Custom Semgrep rules for prompt template validation - Test suite for prompt integrity (future)
License Compliance: - Configure Trivy or Dependency Review to block GPL/AGPL dependencies - MIT license requires freedom from viral license contamination
7b. LLM-Specific Security Vectors (Council v2 Addition)¶
LLM orchestration libraries face unique attack vectors beyond standard AppSec:
Indirect Prompt Injection (RAG): - Malicious content in retrieved documents hijacks model instructions - Mitigation: Separate data vs instructions; treat retrieved text as untrusted input - Custom Semgrep rules to detect unsanitized retrieval → prompt flows
Tool/Function Calling Abuse: - If library allows LLM to call tools (HTTP, shell, DB), risks include: - SSRF via HTTP tools - Command injection via shell execution - Data exfiltration via broad tool permissions - Mitigation: Tool allowlists, argument validation, sandboxing, audit logs
Prompt/Log Leakage: - Orchestrators often log full prompt context for debugging - Risks: API key exposure, PII leakage, proprietary prompt theft - Mitigation: Redaction filters, structured logging with sensitive-field tagging - Default: "no prompt logging" unless explicitly enabled
Cross-Session State Bleed: - Shared caches, vector results, or tool outputs can leak across users - Mitigation: Clear session boundaries, explicit scoping, thread-safe storage
Output Injection: - Model outputs rendered in Markdown/HTML or executed as code - Risks: XSS in UIs, command injection if outputs used unsafely - Mitigation: Output encoding, "never execute model output" documentation
Custom Semgrep Rules (Implement in Phase 2):
rules:
- id: unsafe-pickle-load
patterns:
- pattern: pickle.load(...)
- pattern: torch.load(..., weights_only=False)
message: "Unsafe deserialization - use safetensors or weights_only=True"
severity: ERROR
- id: llm-output-to-exec
patterns:
- pattern: exec($LLM_OUTPUT)
- pattern: eval($LLM_OUTPUT)
message: "Never execute LLM output"
severity: ERROR
- id: unbounded-llm-loop
pattern: |
while True:
... = $LLM.generate(...)
message: "Add iteration limit to LLM generation loop"
severity: WARNING
8. GitHub Dependency Review (Council Addition)¶
Tool: Dependency Review Action (Native) - Blocks PRs that introduce vulnerabilities - License compliance checking - No secrets required (fork-compatible)
Implementation: GitHub Actions Workflows¶
.github/workflows/security.yml¶
name: Security Scanning
on:
push:
branches: [master]
pull_request:
branches: [master]
schedule:
# Run weekly on Monday at 9am UTC
- cron: '0 9 * * 1'
permissions:
contents: read
security-events: write
actions: read
pull-requests: read # Required for dependency review
jobs:
# ============================================================
# Layer 2: PR Security Checks (Fork-Compatible - No Secrets)
# These jobs work on external contributor PRs from forks
# NOTE: Trivy moved to Layer 3 to avoid anonymous rate limits
# ============================================================
codeql:
name: CodeQL Analysis
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: python
# Council recommendation: use security-extended, not security-and-quality
# Avoids blocking PRs on opinionated style issues
queries: security-extended
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
with:
category: "/language:python"
semgrep:
name: Semgrep SAST
runs-on: ubuntu-latest
container:
image: semgrep/semgrep:1.96.0 # Pinned version
steps:
- uses: actions/checkout@v4
# Semgrep for custom rules and fast pattern matching
# CodeQL handles deep semantic analysis (avoid duplicates)
- name: Run Semgrep
run: semgrep scan --config auto --config .semgrep/ --sarif --output semgrep.sarif . || true
- name: Upload Semgrep results
uses: github/codeql-action/upload-sarif@v3
if: always()
with:
sarif_file: semgrep.sarif
gitleaks:
name: Secret Detection
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Run Gitleaks
uses: gitleaks/gitleaks-action@v2.3.7 # Pinned version, no license needed for OSS
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Council Addition: Dependency Review for license compliance
dependency-review:
name: Dependency Review
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
steps:
- uses: actions/checkout@v4
- name: Dependency Review
uses: actions/dependency-review-action@v4
with:
# Use config file for license rules (allows build-time action exceptions)
config-file: ./.github/dependency-review-config.yml
# ============================================================
# Layer 3: Main Branch (post-merge, requires secrets)
# These jobs only run after merge, not on fork PRs
# ============================================================
trivy-sca:
name: Trivy Dependency Scan
runs-on: ubuntu-latest
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
steps:
- uses: actions/checkout@v4
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@0.28.0 # Pinned version
with:
scan-type: 'fs'
scan-ref: '.'
format: 'sarif'
output: 'trivy-results.sarif'
severity: 'CRITICAL,HIGH,MEDIUM'
- name: Upload Trivy scan results
uses: github/codeql-action/upload-sarif@v3
if: always()
with:
sarif_file: 'trivy-results.sarif'
sonarcloud:
name: SonarCloud Analysis
runs-on: ubuntu-latest
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: SonarQube Scan
uses: SonarSource/sonarqube-scan-action@v6 # Pinned version
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
snyk-monitor:
name: Snyk Monitoring
runs-on: ubuntu-latest
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install uv
uses: astral-sh/setup-uv@v5
- name: Install dependencies
run: |
uv pip install --system -e ".[dev]"
- name: Generate requirements.txt for Snyk
run: |
pip freeze > requirements.txt
- name: Run Snyk to monitor
uses: snyk/actions/python@0.4.0 # Pinned version
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
with:
command: monitor
args: --org=amiable-dev --project-name=llm-council --file=requirements.txt
sbom-generate:
name: Generate SBOM
runs-on: ubuntu-latest
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install uv
uses: astral-sh/setup-uv@v5
- name: Install dependencies
run: |
uv pip install --system -e ".[dev]"
- name: Generate SBOM
run: |
pip install cyclonedx-bom==4.6.0
cyclonedx-py environment -o sbom.json --output-format JSON
- name: Upload SBOM artifact
uses: actions/upload-artifact@v4
with:
name: sbom
path: sbom.json
.github/workflows/release-security.yml¶
name: Release Security
on:
release:
types: [published]
permissions:
contents: write
id-token: write
packages: write
jobs:
sbom-attach:
name: Attach SBOM to Release
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Generate SBOM
run: |
pip install cyclonedx-bom==4.6.0
cyclonedx-py environment -o llm-council-${{ github.ref_name }}-sbom.json --output-format JSON
- name: Attach SBOM to release
uses: softprops/action-gh-release@v1
with:
files: llm-council-${{ github.ref_name }}-sbom.json
# Future: Container scanning when Docker image is published
# container-scan:
# name: Scan Container Image
# runs-on: ubuntu-latest
# steps:
# - name: Run Trivy container scan
# uses: aquasecurity/trivy-action@master
# with:
# image-ref: 'ghcr.io/amiable-dev/llm-council:${{ github.ref_name }}'
# format: 'sarif'
# output: 'trivy-container.sarif'
Pre-Commit Configuration¶
.pre-commit-config.yaml¶
repos:
# Existing hooks
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.8.6
hooks:
- id: ruff
args: [--fix]
- id: ruff-format
# Security: Secret detection (fast, catches secrets before commit)
- repo: https://github.com/gitleaks/gitleaks
rev: v8.21.2
hooks:
- id: gitleaks
# Note: Semgrep runs in CI only (too slow for pre-commit)
# CodeQL provides deep analysis in CI
Gitleaks Configuration¶
.gitleaks.toml¶
title = "LLM Council Gitleaks Config"
[extend]
useDefault = true
[[rules]]
id = "openrouter-api-key"
description = "OpenRouter API Key"
regex = '''(?i)(openrouter[_-]?api[_-]?key|sk-or-v1-)[\s'"=:]+[a-zA-Z0-9_-]{32,}'''
tags = ["api", "openrouter"]
[[rules]]
id = "anthropic-api-key"
description = "Anthropic API Key"
regex = '''(?i)(anthropic[_-]?api[_-]?key|sk-ant-)[\s'"=:]+[a-zA-Z0-9_-]{32,}'''
tags = ["api", "anthropic"]
[allowlist]
description = "Global allowlist"
paths = [
'''\.env\.example$''',
'''tests/cassettes/.*\.yaml$''',
'''docs/.*\.md$''',
]
SonarCloud Configuration¶
sonar-project.properties¶
sonar.projectKey=amiable-dev_llm-council
sonar.organization=amiable-dev
sonar.sources=src
sonar.tests=tests
sonar.python.coverage.reportPaths=coverage.xml
sonar.python.version=3.10,3.11,3.12
# Quality gate
sonar.qualitygate.wait=true
Dependabot Configuration¶
.github/dependabot.yml¶
version: 2
updates:
- package-ecosystem: "pip"
directory: "/"
schedule:
interval: "weekly"
day: "monday"
open-pull-requests-limit: 5
groups:
dev-dependencies:
patterns:
- "pytest*"
- "ruff"
- "mypy"
security:
patterns:
- "cryptography"
- "httpx"
- "pyyaml"
labels:
- "dependencies"
- "security"
commit-message:
prefix: "chore(deps)"
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
labels:
- "ci"
- "dependencies"
Security Policy Updates¶
Update SECURITY.md to reference automated scanning:
## Automated Security Scanning
This project uses automated security scanning:
- **Dependency Scanning**: Trivy, Dependabot, Snyk
- **Static Analysis**: CodeQL, Semgrep, SonarCloud
- **Secret Detection**: GitHub Secret Scanning, Gitleaks
Security findings are visible in the GitHub Security tab.
### SBOM
A Software Bill of Materials (SBOM) in CycloneDX format is attached to each release.
README Badge Updates¶
Add security badges:
[](https://snyk.io/test/github/amiable-dev/llm-council)
[](https://scorecard.dev/viewer/?uri=github.com/amiable-dev/llm-council)
[](https://app.fossa.com/projects/git%2Bgithub.com%2Famiable-dev%2Fllm-council)
Implementation Phases¶
Phase 1: GitHub-Native Security (Immediate) - ✅ Complete¶
- [x] Enable GitHub Secret Scanning with push protection (manual: Settings > Security)
- [x] Enable Dependabot for pip ecosystem (
.github/dependabot.yml) - [x] Add CodeQL workflow (security-extended queries)
- [x] Configure Dependabot grouping
- [x] Add Dependency Review Action (license compliance)
- [ ] Configure branch protection with required checks (manual)
Phase 2: Enhanced Scanning + Supply Chain - ✅ Complete¶
- [x] Add Semgrep SAST workflow with LLM-specific rules (fork-compatible)
- [x] Add Gitleaks workflow (fork-compatible)
- [x] Create
.gitleaks.tomlconfig - [x] Update
.pre-commit-config.yaml(Gitleaks + Ruff) - [x] Add SBOM generation (CycloneDX)
- [ ] Add Cosign signing to releases (deferred - requires setup)
- [x] Pin all GitHub Actions by version
- [x] Add custom Semgrep rules for LLM patterns (
.semgrep/llm-security.yaml)
Phase 3: Quality Gates - Main Branch Only - ✅ Complete¶
- [x] Set up SonarCloud project (
sonar-project.properties) - [x] Configure Snyk monitoring workflow
- [x] Add Trivy to main branch only (avoid fork rate limits)
- [x] Add SBOM attachment to releases (
release-security.yml) - [x] Verify fork PRs don't fail due to missing secrets (design verified)
Phase 4: Visibility & Trust - ✅ Complete¶
- [x] Add security badges to README
- [x] Add OpenSSF Scorecard workflow (
.github/workflows/scorecard.yml) - [x] Update SECURITY.md with automation details
- [x] Add SLSA Level 3 provenance attestations (
actions/attest-build-provenance) - [ ] Document security posture in docs site (future)
Phase 5: Advanced Supply Chain (Future)¶
- [x] Add pre-commit hooks documentation (SECURITY.md)
- [ ] Create security testing guide for contributors
- [ ] Add security checklist to PR template
- [ ] Add Garak/Promptfoo LLM red-teaming (when Council Cloud launches)
- [ ] Evaluate Socket.dev for typosquatting detection
Implementation Status¶
Implementation Date: 2025-12-28
Phases 1-4 implemented via GitHub issues #205-#222. Key files created:
- .github/dependabot.yml - Dependency update automation
- .github/dependency-review-config.yml - License rules with build-time action exceptions
- .github/workflows/security.yml - Main security workflow (Layers 2-3)
- .github/workflows/release-security.yml - Release security (Layer 4)
- .github/workflows/scorecard.yml - OpenSSF Scorecard analysis (Phase 4)
- .gitleaks.toml - Custom secret patterns
- .pre-commit-config.yaml - Pre-commit hooks
- .semgrep/llm-security.yaml - LLM-specific SAST rules
- sonar-project.properties - SonarCloud configuration
- tests/test_security_configs.py - TDD tests for configs
- tests/test_security_workflows.py - TDD tests for workflows
Manual Steps Completed:
1. ✅ Enable GitHub Secret Scanning (Settings > Code security and analysis)
2. ✅ Configure branch protection to require security checks
3. ✅ Add SONAR_TOKEN and SNYK_TOKEN to repository secrets
4. ✅ Disable SonarCloud "Automatic Analysis" (conflicts with CI-based analysis)
Consequences¶
Positive¶
- Zero contributor cost: All tools free for public OSS
- Fork-friendly: External PRs work without secrets (Council recommendation)
- Defense in depth: Multiple overlapping scanners
- GitHub-native integration: Findings appear in Security tab
- Supply chain transparency: SBOM with every release
- License compliance: Blocks viral licenses (GPL/AGPL)
- Professional security posture: Badges demonstrate commitment
- Fast feedback: PR checks complete in <5 minutes
Negative¶
- CI time increase: ~3-5 minutes added to PR checks
- Noise potential: May generate false positives initially
- Secret management: Need SNYK_TOKEN, SONAR_TOKEN as repo secrets
- Maintenance: Must keep tool versions updated
Mitigations¶
| Risk | Mitigation |
|---|---|
| CI slowdown | Run scans in parallel, cache where possible |
| False positives | Tune tool configs, use .gitleaksignore |
| Secret sprawl | Use GitHub Environments, document in CONTRIBUTING |
| Version drift | Dependabot updates GitHub Actions too |
Alternatives Considered¶
1. Snyk-Only Approach¶
Use Snyk for SCA, SAST, and container scanning.
Rejected: Free tier limits (200 tests/month) insufficient for active development. GitHub-native tools are more reliable for OSS.
2. Self-Hosted SonarQube¶
Deploy SonarQube instance for analysis.
Rejected: Operational overhead incompatible with OSS goal. SonarCloud is free for public repos.
3. No DAST Until Production¶
Skip DAST entirely.
Accepted: DAST requires running application. Defer to Council Cloud launch.
4. Paid Security Platform¶
Use enterprise platform like Checkmarx or Veracode.
Rejected: Cost barrier for OSS. Free tools provide sufficient coverage.
5. OWASP ZAP for DAST¶
Use fully open source ZAP instead of StackHawk.
Considered for future: ZAP is viable but requires more configuration. Will evaluate when DAST becomes priority.
Council Review Summary (v2)¶
The ADR was reviewed by the LLM Council using high tier (gpt-5.2, claude-opus-4.5, gemini-3-pro-preview, grok-4.1-fast) on 2025-12-28.
Executive Summary¶
The council unanimously agreed that the Layered Architecture (fork-compatible vs secret-requiring) is correctly designed. However, they identified:
- Significant SCA tool redundancy (4 tools doing similar work)
- Weak LLM-specific security coverage (generic AppSec, not LLM AppSec)
- Supply chain hardening should be earlier (SLSA/Signing in Phase 2, not Future)
- Trivy rate limiting risk on fork PRs
Critical Changes Made¶
| Finding | Resolution |
|---|---|
| Trivy may hit rate limits on fork PRs | Rely on Dependency Review for PR blocking; Trivy moved to Layer 3 |
| SCA redundancy (4 tools) | Clarified roles: Dependabot (updates), Dep Review (blocking), Snyk (monitoring) |
| LLM security gaps | Added Section 7b with indirect injection, tool abuse, log leakage |
| SLSA too late | Moved Cosign/SBOM to Phase 2 |
| Missing action pinning | Added SHA pinning requirement to ADR |
LLM-Specific Attack Vectors Added¶
| Vector | Risk | Mitigation |
|---|---|---|
| Indirect Prompt Injection (RAG) | Critical | Separate data vs instructions; trust boundaries |
| Tool/Function Abuse | Critical | Tool allowlists, argument validation, sandboxing |
| Prompt/Log Leakage | High | Redaction filters, no-prompt-logging defaults |
| Cross-Session State Bleed | Medium | Clear session boundaries, scoped storage |
| Output Injection (XSS/Command) | High | Output encoding, never execute model output |
Recommendations Deferred¶
| Recommendation | Reason |
|---|---|
| Garak/Promptfoo LLM red-teaming | No runtime API yet; implement with Council Cloud |
| Socket.dev for typosquatting | pip-audit covers basic cases; Socket is Phase 5 |
Council Review Summary (v1)¶
The ADR was reviewed by the LLM Council using reasoning tier (openai/o1, google/gemini-3-pro-preview) on 2025-12-28. Key findings and changes:
Critical Issue Resolved: Fork Compatibility¶
Problem Identified: External contributor PRs from forks cannot access repository secrets (SNYK_TOKEN, SONAR_TOKEN). The original design would fail CI on every fork PR.
Resolution:
- Layer 2 (PR checks) now uses only token-less tools (CodeQL, Trivy, Gitleaks, Dependency Review)
- Layer 3 (Snyk, SonarCloud) moved to push: master only
- Added clear comments in workflow separating fork-compatible vs secret-requiring jobs
Council Recommendations Implemented¶
| Recommendation | Change Made |
|---|---|
| Pin action versions | All @master refs replaced with specific versions |
| Remove GITLEAKS_LICENSE | Removed (unnecessary for OSS) |
| Use security-extended | Changed from security-and-quality to avoid style blocking |
| Add Dependency Review | Added with license compliance (blocks GPL/AGPL) |
| LLM-specific security | Added Section 7 covering model serialization, prompt injection |
| Document tool roles | Added comments clarifying Semgrep vs CodeQL scope |
Recommendations Deferred¶
| Recommendation | Reason |
|---|---|
| Modelscan/Picklescan | LLM Council doesn't load external model weights |
| Custom Semgrep rules for prompts | Create after establishing patterns |
Recommendations Implemented (Post-Review)¶
| Recommendation | Implementation |
|---|---|
| SLSA/Sigstore provenance | Implemented as SLSA Level 3 in Phase 4 using actions/attest-build-provenance |