Skip to main content

Documentation Index

Fetch the complete documentation index at: https://tally.wharflab.com/llms.txt

Use this file to discover all available pages before exploring further.

A Rails secret name (SECRET_KEY_BASE, RAILS_MASTER_KEY, DEVISE_SECRET_KEY, etc.) is declared via ARG or ENV with a non-placeholder value, baking the secret into image history.
PropertyValue
SeverityError
CategorySecurity
DefaultEnabled
Auto-fixNo edit (suggestion only)

Description

Rails secrets declared via ARG or ENV end up in image history. docker history --no-trunc <image> and any registry that proxies image manifests will leak them. Anyone who can pull the image can recover the secret. This rule fires on the following env-var names — the Rails core canonical secrets plus Devise’s:
  • SECRET_KEY_BASE
  • RAILS_MASTER_KEY
  • SECRET_TOKEN (legacy Rails 4.x)
  • DEVISE_SECRET_KEY
  • DEVISE_PEPPER
  • RAILS_KEY (alternate alias seen in some apps)
The rule fires for both ARG and ENV, including:
  • ENV SECRET_KEY_BASE="abc123" — value baked into image layer history.
  • ARG SECRET_KEY_BASE=value — value baked into both layer history (when consumed via RUN) and the build cache key data.
  • ARG SECRET_KEY_BASE (no default) — still flagged. The user is meant to pass --build-arg SECRET_KEY_BASE=..., which adds the secret to build cache key data and (when consumed via RUN/ENV) leaks it into image history.
  • Meta-ARG (before any FROM).

Compliance

The rule treats =1, ="1", ="dummy", and ="SECRET_KEY_BASE_DUMMY" (case-insensitive) as compliant placeholder values — these match Rails 7.1+‘s build-time placeholder contract for asset compilation. SECRET_KEY_BASE_DUMMY=1 is the supported way to run bin/rails assets:precompile without a real key. Stages explicitly named dev/development/test/testing/ci/debug are skipped. Use BuildKit’s secret-mount syntax: secrets exist for the duration of one RUN, never appear in image content, and are not part of the cache key.
RUN --mount=type=secret,id=rails_master_key,env=RAILS_MASTER_KEY \
    bundle exec rails db:schema:load
For asset compilation specifically, SECRET_KEY_BASE_DUMMY=1 (Rails 7.1+) avoids needing the real key at build time entirely:
RUN SECRET_KEY_BASE_DUMMY=1 ./bin/rails assets:precompile
This is also caught by tally/ruby/asset-precompile-without-dummy-key, which is the structural fix for build-time SECRET_KEY_BASE.

Examples

Before

FROM ruby:3.3-slim
ARG RAILS_MASTER_KEY
ENV RAILS_MASTER_KEY=$RAILS_MASTER_KEY
RUN bundle exec rails db:schema:load

After

FROM ruby:3.3-slim
RUN --mount=type=secret,id=rails_master_key,env=RAILS_MASTER_KEY \
    bundle exec rails db:schema:load
Pass the secret at build time with:
docker buildx build --secret id=rails_master_key,src=$HOME/.ssh/rails_master_key .

Auto-fix

The rule emits a no-edit FixUnsafe suggestion: the description points the user at the BuildKit secret-mount pattern. The actual rewrite depends on the user’s CI / vault / secret-injection setup, so the rule cannot auto-rewrite.

References