Skip to content

fix(security): replace APPS_JSON_BASE64 build-arg with BuildKit secret#1861

Open
OmarElaraby26 wants to merge 2 commits intofrappe:mainfrom
OmarElaraby26:fix/apps-json-token-leak
Open

fix(security): replace APPS_JSON_BASE64 build-arg with BuildKit secret#1861
OmarElaraby26 wants to merge 2 commits intofrappe:mainfrom
OmarElaraby26:fix/apps-json-token-leak

Conversation

@OmarElaraby26
Copy link
Copy Markdown

Summary

  • Replace ARG APPS_JSON_BASE64 / --build-arg with BuildKit --mount=type=secret in both custom and layered Containerfiles
  • Update docs (02-build-setup.md, 08-single-server-nginxproxy-example.md) to use --secret instead of --build-arg

Details

When building custom images with private apps, apps.json (which may contain GitHub PATs in repository URLs) is currently passed as --build-arg=APPS_JSON_BASE64. Docker build
arguments are permanently stored in image layer metadata and visible to anyone with image access via docker image history --no-trunc. This means private repo tokens are
trivially extractable from any built image.

This is a known Docker anti-pattern: SecretsUsedInArgOrEnv.

The fix uses BuildKit secret mounts (--mount=type=secret), which makes apps.json available only during the RUN step — it is never committed to any layer. The change is
backward compatible: when no secret is provided, the build proceeds without apps.json (same as before when APPS_JSON_BASE64 was empty).

Fixes #1860

Test plan

  • Built custom image with --secret=id=apps_json,src=apps.json containing private repos — build succeeded
  • Verified docker image history --no-trunc shows no tokens in any layer
  • Deployed full stack (MariaDB, Redis, frontend, backend, workers) and created a site with erpnext, education, payments, lms — all working
  • Verified build still works when no secret is provided (no apps.json)

…t mount

APPS_JSON_BASE64 is stored in image layer metadata, permanently exposing
private repo tokens (GitHub PATs) to anyone with image pull access.

Replace --build-arg with --mount=type=secret so that apps.json is only
available during the RUN step and never committed to any layer.

Refs: https://docs.docker.com/reference/build-checks/secrets-used-in-arg-or-env/
@DanielRadlAMR
Copy link
Copy Markdown
Collaborator

DanielRadlAMR commented Apr 7, 2026

Instead of setting DOCKER_BUILDKIT=1, I’d suggest explicitly stating that Docker Engine v23+ is required.

BuildKit has been the default builder since Docker Engine 23.0 (Feb 2023),
so prefixing the example build commands with DOCKER_BUILDKIT=1 is redundant
on any supported install. Replace the prefix with an explicit prerequisite
note so the requirement lives with the user's environment, not the example.

The build relies on BuildKit secret mounts (--secret) to keep apps.json
tokens out of image layers, which is why a real BuildKit-default engine
is mandatory rather than merely recommended.

Addresses review feedback on PR frappe#1861.
@OmarElaraby26
Copy link
Copy Markdown
Author

@DanielRadlAMR Thanks for the suggestion, agreed, and applied in the latest commit

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(security): APPS_JSON_BASE64 build-arg leaks private repo tokens in image layer metadata

2 participants