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

ComponentRiskMitigation
LLM callsRequirements data is sent to the LLM providerredact_patterns to remove sensitive data; local models for air-gapped environments
Source filesSources may contain secrets, PII, regulated dataredact_files excludes sensitive files; redaction before sending
Connector credentialsAPI tokens for Jira/Confluence/GitHubEnvironment variables, never in .intake.yaml; transparent rotation
acceptance.yamlChecks of type command execute arbitrary shell commandsReview checks before running intake verify; do not run specs from untrusted sources
Plugin systemExternal plugins execute Python codeOnly install plugins from trusted sources; intake plugins check to validate
spec.lock.yamlContains hashes and metadata from sourcesOnly 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)

Stays 100% local:

  • intake verify — check execution
  • intake export — file generation
  • intake show, list, diff — file reading
  • intake doctor — environment checks
  • intake task — state management
  • intake 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 runs. When rotating a credential:

  1. Update the environment variable value
  2. The next intake run will automatically use the new value

Secrets in CI/CD

PlatformMechanismExample
GitHub Actionssecrets.*${{ secrets.ANTHROPIC_API_KEY }}
GitLab CICI/CD Variables (masked)$ANTHROPIC_API_KEY
JenkinsCredentials pluginwithCredentials([string(...)])
Azure DevOpsVariable groups (secret)$(ANTHROPIC_API_KEY)

See CI/CD Integration for complete examples.


Sensitive data redaction

Redaction patterns (redact_patterns)

Patterns are regex applied to 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"

Verifying redaction

To verify that patterns work correctly:

  1. Run with --dry-run to see which sources would be processed
  2. Review spec.lock.yaml to confirm which files were processed (only hashes, not content)
  3. Use --preset minimal with a test source to see the output

Offline / air-gapped mode

Commands by connectivity mode

CommandRequires internetOffline alternative
intake initYes (LLM)Local model (Ollama, vLLM)
intake addYes (LLM)Local model
intake feedbackYes (LLM)Local model
intake verifyNoWorks offline
intake exportNoWorks offline
intake showNoWorks offline
intake listNoWorks offline
intake diffNoWorks offline
intake doctorNoWorks offline
intake taskNoWorks offline
intake pluginsNoWorks offline
API connectorsYes (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):

FrameworkModel configExample
Ollamaollama/<model>ollama/llama3, ollama/mistral
vLLMvllm/<model>vllm/meta-llama/Llama-3-8b
Local OpenAI-compatibleopenai/<model> + api_baseAny OpenAI-compatible server

Considerations:

  • Extraction quality depends on the model; larger models produce better specs
  • Local models can be significantly slower
  • Adjust timeout in the configuration for slow models

Pattern: pre-generate specs for teams without LLM

If only one person has access to the LLM:

# 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:

FieldWhat it containsAudit value
created_atISO timestampWhen the spec was generated
modelLLM model usedReproducibility
config_hashConfiguration hashParameter consistency
source_hashesSHA-256 of each source (16 hex)Source integrity
spec_hashesSHA-256 of each spec fileOutput integrity
total_costCost in USDExpense tracking
requirement_countNumber of requirementsMetrics
task_countNumber of tasksMetrics

Pattern: verify source integrity

If sources change after generating the spec, 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

CapabilityDescription
Requirement-to-source traceabilitysources.md maps each requirement to its origin
Immutable audit artifactspec.lock.yaml with hashes and timestamps
Automated verificationacceptance.yaml with executable checks
Sensitive data redactionConfigurable redact_patterns and redact_files
Offline modeEverything except init/add/feedback works without internet
Local modelsSupport for Ollama, vLLM (data never leaves the network)
VersioningSpecs as text files, ideal for git
Reproducibilityspec.lock.yaml records configuration, model, and costs

What intake does NOT provide

AspectStatus
Data encryption in transitDepends on the LLM provider (HTTPS)
Access control for specsDepends on the file system / git
Access logsDoes not generate logs of who accesses the specs
Compliance certificationintake is not a certified tool
Data encryption at restDepends on the file system
Automatic data retentionHas no retention policies; files persist until deleted

Recommendations by framework

FrameworkRecommendations with intake
SOC2Use redact_patterns + commit spec.lock.yaml + maintain git history of specs + JUnit in CI as evidence
HIPAALocal model (air-gapped) + aggressive PHI redaction + never use connectors with patient data + review specs manually
ISO 27001Document intake in asset inventory + use enterprise preset + enable generate_lock + redact internal IPs and hostnames
GDPRRedact 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)
  • .env added to .gitignore
  • redact_patterns configured for the project’s data types
  • redact_files includes the project’s credential patterns
  • Specs reviewed before sharing externally
  • acceptance.yaml reviewed before running verify (command checks)
  • Only plugins from trusted sources installed
  • spec.lock.yaml committed alongside specs
  • CI/CD uses secrets management for API keys
  • Local model evaluated if data is sensitive