Security
Security guide for using intake in corporate and regulated environments. Covers the threat model, secret management, sensitive data redaction, offline mode, and compliance considerations.
Threat model
Attack surface
| Component | Risk | Mitigation |
|---|---|---|
| LLM calls | Requirement data is sent to the LLM provider | redact_patterns to remove sensitive data; local models for air-gapped environments |
| Source files | Sources may contain secrets, PII, regulated data | redact_files excludes sensitive files; redaction before sending |
| Connector credentials | API tokens for Jira/Confluence/GitHub | Environment variables, never in .intake.yaml; transparent rotation |
| acceptance.yaml | Checks of type command execute arbitrary shell commands | Review checks before running intake verify; do not run specs from untrusted sources |
| Plugin system | External plugins execute Python code | Only install plugins from trusted sources; intake plugins check to validate |
| spec.lock.yaml | Contains hashes and metadata of the sources | Only partial hashes (16 hex chars), not content; safe to commit |
Data flow: what is sent to the LLM
Requirement sources
|
[ REDACTION ] <-- security.redact_patterns (regex)
[ EXCLUSION ] <-- security.redact_files (glob)
|
Clean text + metadata
|
[ SENT TO LLM ] <-- Only init, add, feedback
|
JSON response (requirements, design, tasks)
|
[ LOCAL GENERATION ] <-- Everything else is local
|
Spec files (Markdown/YAML)
Sent to the LLM:
- Text extracted from sources (after redaction)
- Tech stack information (auto-detected)
- Configured language
NOT sent to the LLM:
- Project source code
- API keys or credentials
- Content of files excluded by
redact_files - Verification results (except in
feedback)
Remains 100% local:
intake verify— check executionintake export— file generationintake show,list,diff— file readingintake doctor— environment checksintake task— state managementintake plugins— plugin listing
Secret management
LLM API keys
API keys are always read from environment variables. They are never stored in .intake.yaml:
# .intake.yaml — only the variable NAME, not the value
llm:
api_key_env: ANTHROPIC_API_KEY
# Set the environment variable
export ANTHROPIC_API_KEY=sk-ant-api03-...
Recommended pattern for teams:
# .env (in .gitignore — never commit)
ANTHROPIC_API_KEY=sk-ant-api03-your-real-key
# .env.example (commit as reference)
ANTHROPIC_API_KEY=sk-ant-api03-REPLACE
Connector tokens
Same pattern for Jira, Confluence, and GitHub:
# .env
JIRA_API_TOKEN=your-jira-token
JIRA_EMAIL=dev@company.com
CONFLUENCE_API_TOKEN=your-confluence-token
CONFLUENCE_EMAIL=dev@company.com
GITHUB_TOKEN=ghp_your-personal-access-token
Variable names are configurable in .intake.yaml via connectors.*.token_env and connectors.*.email_env.
Credential rotation
intake does not cache tokens between executions. When rotating a credential:
- Update the environment variable value
- The next intake execution will automatically use the new value
Secrets in CI/CD
| Platform | Mechanism | Example |
|---|---|---|
| GitHub Actions | secrets.* | ${{ secrets.ANTHROPIC_API_KEY }} |
| GitLab CI | CI/CD Variables (masked) | $ANTHROPIC_API_KEY |
| Jenkins | Credentials plugin | withCredentials([string(...)]) |
| Azure DevOps | Variable groups (secret) | $(ANTHROPIC_API_KEY) |
See CI/CD Integration for complete examples.
Sensitive data redaction
Redaction patterns (redact_patterns)
Patterns are regex applied to the source text before sending it to the LLM:
security:
redact_patterns:
# API keys and tokens
- "sk-[a-zA-Z0-9]{20,}" # Anthropic API keys
- "sk-proj-[a-zA-Z0-9]{20,}" # OpenAI project keys
- "ghp_[a-zA-Z0-9]{36}" # GitHub PATs
- "xoxb-[a-zA-Z0-9-]+" # Slack bot tokens
- "AKIA[0-9A-Z]{16}" # AWS access keys
# Financial data
- "\\b\\d{4}[- ]?\\d{4}[- ]?\\d{4}[- ]?\\d{4}\\b" # Card numbers
- "\\b\\d{3}-\\d{2}-\\d{4}\\b" # SSN (US)
# Credentials in text
- "password\\s*[:=]\\s*['\"]?\\S+" # Passwords in configs
- "secret\\s*[:=]\\s*['\"]?\\S+" # Secrets in configs
- "mongodb(\\+srv)?://[^\\s]+" # MongoDB connection strings
- "postgres(ql)?://[^\\s]+" # PostgreSQL connection strings
- "mysql://[^\\s]+" # MySQL connection strings
# Internal data
- "\\b\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b" # Internal IPs
File exclusion (redact_files)
Files that intake will never process as sources:
security:
redact_files:
# Defaults
- "*.env"
- "*.pem"
- "*.key"
# Recommended for enterprise
- "credentials.*"
- "secrets.*"
- "*.pfx"
- "*.p12"
- "*.jks"
- "docker-compose.override.yml"
- ".env.*"
- "*.secret"
Verify the redaction
To verify that patterns are working correctly:
- Run with
--dry-runto see which sources would be processed - Review
spec.lock.yamlto confirm which files were processed (only hashes, not content) - Use
--preset minimalwith a test source to see the output
Offline / air-gapped mode
Commands by connection mode
| Command | Requires internet | Offline alternative |
|---|---|---|
intake init | Yes (LLM) | Local model (Ollama, vLLM) |
intake add | Yes (LLM) | Local model |
intake feedback | Yes (LLM) | Local model |
intake verify | No | Works offline |
intake export | No | Works offline |
intake show | No | Works offline |
intake list | No | Works offline |
intake diff | No | Works offline |
intake doctor | No | Works offline |
intake task | No | Works offline |
intake plugins | No | Works offline |
| API connectors | Yes (external APIs) | Not available offline |
Local models for air-gapped environments
# .intake.yaml for Ollama
llm:
model: ollama/llama3
api_key_env: DUMMY_KEY # Ollama does not need a key
timeout: 300 # Local models can be slower
export DUMMY_KEY=not-needed
# Verify that Ollama is running
ollama list
# Generate spec with local model
intake init "Feature" -s reqs.md
Supported local models (via LiteLLM):
| Framework | Model config | Example |
|---|---|---|
| Ollama | ollama/<model> | ollama/llama3, ollama/mistral |
| vLLM | vllm/<model> | vllm/meta-llama/Llama-3-8b |
| Local OpenAI-compatible | openai/<model> + api_base | Any OpenAI-compatible server |
Considerations:
- Extraction quality depends on the model; larger models produce better specs
- Local models can be significantly slower
- Adjust
timeoutin the configuration for slow models
Pattern: pre-generate specs for teams without LLM access
If only one person has LLM access:
# Person with LLM access generates the specs
intake init "Feature" -s reqs.md
git add specs/ && git commit -m "Add feature spec"
git push
# Team without LLM uses verify, export, task (all offline)
git pull
intake verify specs/feature/ -p .
intake export specs/feature/ -f claude-code -o .
intake task list specs/feature/
Auditing and traceability
spec.lock.yaml as an audit artifact
Each spec includes a spec.lock.yaml that records:
| Field | Contents | Audit value |
|---|---|---|
created_at | ISO timestamp | When the spec was generated |
model | LLM model used | Reproducibility |
config_hash | Hash of the configuration | Parameter consistency |
source_hashes | SHA-256 of each source (16 hex) | Source integrity |
spec_hashes | SHA-256 of each spec file | Output integrity |
total_cost | Cost in USD | Expense tracking |
requirement_count | Number of requirements | Metrics |
task_count | Number of tasks | Metrics |
Pattern: verify source integrity
If sources change after the spec is generated, spec.lock.yaml detects it:
intake show specs/feature/
# If sources changed, shows staleness warning
Change history via git
Specs are text files ideal for versioning:
# Compare versions
intake diff specs/feature-v1/ specs/feature-v2/
# Change history
git log --oneline specs/feature/
# Who changed what
git blame specs/feature/requirements.md
Bidirectional traceability
intake provides complete requirement-to-source traceability:
Original source (reqs.md, jira.json)
↓ (recorded in sources.md)
Requirement (FR-001 in requirements.md)
↓ (referenced in tasks.md)
Task (Task 1: implement FR-001)
↓ (checks in acceptance.yaml)
Verification (check-01: tests pass)
↓ (results in verify report)
Compliance evidence
The sources.md file maps each requirement to its original source, providing the traceability that audits require.
Compliance considerations
What intake provides
| Capability | Description |
|---|---|
| Requirement-to-source traceability | sources.md maps each requirement to its origin |
| Immutable audit artifact | spec.lock.yaml with hashes and timestamps |
| Automated verification | acceptance.yaml with executable checks |
| Sensitive data redaction | Configurable redact_patterns and redact_files |
| Offline mode | Everything except init/add/feedback works without internet |
| Local models | Support for Ollama, vLLM (data never leaves the network) |
| Versioning | Specs as text files, ideal for git |
| Reproducibility | spec.lock.yaml records configuration, model, and costs |
What intake does NOT provide
| Aspect | Status |
|---|---|
| Data encryption in transit | Depends on the LLM provider (HTTPS) |
| Access control for specs | Depends on the file system / git |
| Access logs | Does not generate logs of who accesses the specs |
| Compliance certification | intake is not a certified tool |
| Data encryption at rest | Depends on the file system |
| Automatic data retention | Has no retention policies; files persist until deleted |
Recommendations by framework
| Framework | Recommendations with intake |
|---|---|
| SOC2 | Use redact_patterns + commit spec.lock.yaml + maintain git history of specs + JUnit in CI as evidence |
| HIPAA | Local model (air-gapped) + aggressive PHI redaction + never use connectors with patient data + manually review specs |
| ISO 27001 | Document intake in asset inventory + use enterprise preset + enable generate_lock + redact internal IPs and hostnames |
| GDPR | Redact PII from sources before processing + local model if data cannot leave the jurisdiction + document legal basis for processing |
Security checklist for teams
- API keys configured via environment variables (not in
.intake.yaml) -
.envadded to.gitignore -
redact_patternsconfigured for the project’s data types -
redact_filesincludes the project’s credential patterns - Specs reviewed before sharing externally
-
acceptance.yamlreviewed before runningverify(commandchecks) - Only plugins from trusted sources installed
-
spec.lock.yamlcommitted alongside the specs - CI/CD uses secrets management for API keys
- Local model evaluated if data is sensitive