Skip to main content

Secrets security

This page describes the security model for Loom secrets: what it protects, how protection works, and what you are responsible for.

Read this page if you are evaluating Loom for production use, configuring secrets providers, or responding to a suspected credential leak.

Security goals

Loom's secrets system is designed around four objectives:

  1. No secret bytes in static artifacts. Workflow YAML, Graph IR, compiled output, and receipts contain references only.
  2. Minimal runtime exposure. Resolved values exist in memory only for the duration of injection and are discarded after the job finishes.
  3. Fail closed on unsafe conditions. Missing provider auth, invalid references, and dangerous debug configurations all produce hard failures — never silent fallbacks.
  4. Shareable logs. Automatic redaction ensures logs and receipts can be shared for debugging without exposing secret values.

Threat model

Protected assets

AssetExamples
Secret valuesPasswords, API tokens, signing keys, connection strings
Vault credentialsKeePass master passwords, keyfiles, 1Password service account tokens
Vault topologyEntry paths, vault names, and organizational structure

Threat scenarios

ThreatAttack pathLoom control
Credential in CI logsecho, set -x, or command-line interpolation prints a secretFile-first injection (file: true) prevents value from appearing in command lines; redaction scrubs output boundaries
Credential in artifactsSecret stored as a plain variable ends up in compiled YAML or receiptsSecrets use reference-only storage; schema rejects overlapping variables and secrets keys
Auth material in sourceMaster password or service account token committed in workflow YAMLProvider architecture requires runtime-only credential configuration; no workflow field accepts vault auth material
Provider fallback driftA missing provider silently falls back to a weaker credential sourceProviders fail closed with SECRETS_PROVIDER_UNAVAILABLE; no implicit fallback chain exists
Debug trace leaks direct valuesCI_DEBUG_TRACE=true enables shell tracing that can expose file: false secretsHard failure (SECRETS_UNSAFE_DEBUG_TRACE) before job execution when this combination is detected

Core controls

1. References-only workflows

Workflow YAML stores ref URIs, not values. This prevents secret bytes from entering source control, loom compile output, or receipt artifacts. The separation is enforced at the schema level — there is no field that accepts inline secret values.

2. Job-scoped declaration

Secrets are allowed only at the job level. default.secrets is rejected by the schema validator to prevent a single declaration from fanning out sensitive material to every job in the workflow.

3. File-first injection

file: true is the default. The resolved value is written to a temporary file with 0600 permissions, and the environment variable is set to the file path. This prevents secret values from appearing in:

  • Shell trace output (set -x)
  • Process listings (ps aux)
  • Command-line argument logs
  • Docker inspect output

For Docker jobs, file-injected secrets are bind-mounted read-only into the container.

4. Redaction at output boundaries

Before writing to any output surface, Loom replaces resolved secret values with stable redaction tokens:

[REDACTED:SECRET_DATABASE_PASSWORD]

Redacted surfaces include console streams, receipt stdout/stderr, error fields, and provider lifecycle messages.

Limitation: Redaction operates on exact byte matching. If a script transforms a secret value (e.g., base64-encodes it) before printing, the transformed output will not be redacted. Treat redaction as defense-in-depth, not a guarantee.

5. Fail-closed provider behavior

When provider auth or configuration is missing or invalid, resolution fails immediately with a deterministic SECRETS_* error code. There is no silent fallback to alternate providers, implicit credentials, or empty values.

Provider-specific security notes

env://

  • Risk profile: The host process environment may contain values visible to unrelated tooling or inherited by child processes.
  • Guidance: Use env:// only for values already secured at the runner or session boundary. Avoid long-lived shell sessions with broadly exported secrets.

keepass://

  • Risk profile: Security depends on local filesystem hygiene and unlock credential handling. A compromised keyfile or weak master password undermines all entries.
  • Guidance:
    • Map aliases through runtime config environment variables (LOOM_KEEPASS_DB_<ALIAS>_PATH).
    • Use credential indirection (..._PASSWORD_ENV, ..._KEYFILE_ENV) — never place master passwords in workflow YAML.
    • Restrict filesystem permissions on .kdbx files and keyfiles.

op://

  • Risk profile: Security depends on the 1Password service account token scope and rotation.
  • Guidance:
    • Use least-privilege token scoping — grant access only to the vaults and items required.
    • Rotate service account tokens on a defined schedule.
    • Keep OP_SERVICE_ACCOUNT_TOKEN out of workflow YAML and variables blocks.

Operational guardrails

GuidelineRationale
Prefer file: true for all secretsReduces leakage surface from shell tracing, ps, and interpolation
Disable CI_DEBUG_TRACE on secrets-heavy jobsPrevents hard failure and avoids accidental exposure of file: false values
Avoid printing secret env vars in scriptsRedaction is defense-in-depth, not foolproof
Rotate provider credentials independentlyWorkflow updates and credential rotation should be decoupled
Validate workflows before runningloom check catches schema violations, invalid refs, and scope conflicts

Debug-trace safety

When CI_DEBUG_TRACE=true and any secret uses file: false, Loom hard-fails with SECRETS_UNSAFE_DEBUG_TRACE before execution begins. This prevents shell traces from printing direct-injected secret values.

To debug a job that uses direct-injected secrets, either switch the secrets to file: true or remove CI_DEBUG_TRACE.

Incident response

If you suspect a secret has leaked:

  1. Revoke immediately. Rotate the exposed credential at the source provider (1Password, KeePass, environment).
  2. Scope the exposure. Identify the run ID and job, then check logs and receipts for the redaction token to confirm whether the raw value appeared.
  3. Assess downstream impact. Determine whether the leaked value was consumed by external systems or persisted to external sinks.
  4. Patch the source. Fix the workflow or script pattern that caused the leak — typically switching from file: false to file: true or removing an echo statement.
  5. Verify the fix. Re-run with redaction verification before restoring normal operation.

Security review checklist (for contributors)

When adding a new secrets provider, verify:

  • Provider contract includes explicit auth-source policy and allowlisting.
  • Resolver fails closed on unavailable or invalid auth.
  • No secret bytes are written to planner, receipt, or event artifacts.
  • Redaction test coverage includes quoted and newline variants.
  • Error codes are deterministic and do not contain sensitive content.
  • Documentation covers setup, runtime boundaries, and risk caveats.