
Укреплённый пакет dasel v3.3.1 и образ, собранные с помощью Melange и apko. Патчинг CVE-2026-33320.
Это пакет melange и образ контейнера apko для dasel v3.3.1 с патчем на этапе сборки для CVE-2026-33320 (неограниченное разворачивание алиасов YAML). Образ полностью собирается из локально созданного APK — не используется ни один предварительно собранный образ из вышестоящего репозитория.
| Инструмент | Протестированная версия | Назначение |
|---|---|---|
| Docker | 29.3.1 | Среда выполнения контейнеров, запускает melange/apko через compose.yaml |
| melange | 0.50.5 (Docker image cgr.dev/chainguard/melange@sha256:b6f11bb45a6090c182986028fd2249fb1a18dcb6e173c4ce001dd3fb4cb1dd71) | Сборщик APK-пакетов |
| apko | 1.2.10 (Docker image cgr.dev/chainguard/apko@sha256:20dfc1f5e3461b5eaf3279f762cd4bf86c7f3635d2a9642f905cf583525f9ee6) | Сборщик OCI-образов |
Все команды сборки и загрузки работают в любом терминале (PowerShell, CMD или bash). Один шаг по-прежнему требует командную оболочку Unix:
bash tests/test.sh — тестовый скрипт использует bash и coreutils (timeout, grep, sed)Установите Git Bash (поставляется вместе с Git for Windows) перед запуском тестов образа.
.
├── .github/
├── melange/
│ ├── dasel.yaml
│ └── CVE-2026-33320.patch
├── apko/
│ └── dasel.yaml
├── tests/
│ └── test.sh
├── Makefile
├── compose.yaml
├── keys/ # Generated, gitignored
│ ├── melange.rsa
│ └── melange.rsa.pub
├── sbom/ # Generated, gitignored
│ ├── sbom-x86_64.spdx.json
│ └── sbom-index.spdx.json
├── packages/ # Generated, gitignored
│ └── x86_64/
│ ├── dasel-3.3.1-r0.apk
│ └── APKINDEX.tar.gz
└── README.md
make build # keygen (if needed) + package + image
make test # package tests + image tests
make all # build + test
make clean # remove all generated artifacts
make help # list all targets and variables
# 1. Generate signing keys (one-time)
docker compose run --rm melange keygen keys/melange.rsa
# 2. Build the APK package (fetches source, applies CVE patch, compiles)
docker compose run --rm melange build melange/dasel.yaml --arch x86_64 --signing-key keys/melange.rsa
# 3. Build the OCI image (consumes the local APK)
docker compose run --rm apko build apko/dasel.yaml dasel:3.3.1 dasel.tar --arch x86_64 --sbom-path sbom/
Шаг 2 автоматически создаёт и подписывает packages/x86_64/APKINDEX.tar.gz.
После загрузки образа запустите dasel:
docker load --input dasel.tar
# Example: query a JSON file
echo '{"name": "dasel"}' | docker run --rm \
--read-only \
--cap-drop=ALL \
--security-opt=no-new-privileges \
-i dasel:3.3.1-amd64 \
-i json 'name'
Эти флаги обеспечивают уровень безопасности на этапе выполнения в рамках стратегии эшелонированной защиты, описанной в разделе Усиление образа: неизменяемая корневая файловая система, нулевые возможности Linux и отсутствие путей повышения привилегий.
make test # all tests (package + image)
make package-test # melange package tests only
make image-test # image tests only (requires bash)
# Package tests
docker compose run --rm melange test melange/dasel.yaml --arch x86_64
# Image tests (requires Git Bash on Windows)
docker load --input dasel.tar
bash tests/test.sh
Тестовый скрипт проверяет:
dasel version сообщает v3.3.1-i json 'test')-i json -o yaml --root)"yaml expansion budget exceeded" вместо зависанияУязвимость позволяет неограниченно потреблять ресурсы ЦП/памяти через экспоненциально вложенные алиасы YAML (атака «billion laughs»). Патч из melange/CVE-2026-33320.patch добавляет в модуль чтения YAML в dasel два механизма защиты: ограничение глубины разворачивания (32), которое ограничивает рекурсивную вложенность алиасов, и бюджет разворачивания (1000), который ограничивает общее количество разыменований алиасов на документ. При достижении любого из лимитов декодирование немедленно возвращает ошибку.
-trimpath для удаления локальных путей сборкиОбраз применяет эшелонированную защиту, выходящую за рамки минимальной сборки:
Готовый образ (dasel.tar) был просканирован с помощью отраслевых стандартных инструментов для проверки уровня безопасности помимо самого патча CVE.
С помощью Syft из образа было извлечено 36 пакетов путём анализа метаданных модулей Go-бинарного файла:
wolfi-baselayout 20230201-r29, ca-certificates-bundle 20260413-r0, dasel 3.3.1-r0go.yaml.in/yaml/v4, github.com/hashicorp/hcl/v2, github.com/pelletier/go-toml/v2, github.com/goccy/go-json, github.com/charmbracelet/bubbletea, golang.org/x/sys, golang.org/x/text, stdlib go1.25.9 и ещё 25/usr/bin/dasel, /etc/ssl/certs/ca-certificates.crt, база APK, отдельные SBOM для каждого пакета и файлы конфигурации baselayoutSBOM, который я создал, был проверен с помощью Grype, и никаких других уязвимостей не обнаружено ни в одном из 32 модулей Go или 3 APK-пакетов.
--arch.gitignore. В production-среде приватные ключи подписи должны храниться в менеджере секретов, а не в локальной файловой системе, даже если файлы, игнорируемые git, могут быть раскрыты через инструменты резервного копирования, монтирование томов контейнера или скомпрометированную рабочую станциюbusybox, go, ca-certificates-bundle). Если в любом из этих вышестоящих пакетов будет обнаружена уязвимость, она затронет и этот образ. В production будет необходимо поддерживать пакеты Wolfi в актуальном состоянии или подписаться на их бюллетени безопасностиcompose.yaml. Разработка велась на Kali 2025.3 и проверена на Windows 10 с Docker Desktop 29.3.1tests/test.sh использует timeout (coreutils) и Docker CLI. Все остальные команды — чистый docker и работают из PowerShell или CMD. В Windows запускайте тестовый скрипт из Git Bash (см. )apko автоматически создаёт SPDX-SBOM во время сборки в папке sbom/ (sbom/sbom-x86_64.spdx.json, sbom/sbom-index.spdx.json). Они отслеживают 3 установленных APK-пакета с версиями, CPE, информацией о происхождении исходников и ссылками на определения сборки Melange. Однако они не включают зависимости модулей Go, скомпилированные в бинарный файл dasel. Я решил их просканировать и использовал Syft для закрытия этого пробела, извлекая все 32 модуля Go из встроенных метаданных бинарного файла.
Для production-среды стоило бы автоматизировать извлечение SBOM с периодической проверкой. Затем, возможно, прикрепить результаты SBOM к чему-то вроде https://github.com/nedlir/CVEnotifier, который я написал на Golang для поиска новых уязвимостей в цепочке поставок.
Сборка для нескольких архитектур — поддержка нескольких архитектур для сборки этого контейнера.
CI/CD конвейер — автоматизация сборки и тестирования в GitHub Actions с помощью container actions для melange/apko.
SBOM на уровне Go в melange — запуск syft в процессе сборки melange и встраивание SBOM модулей Go рядом с APK.
| Уровень | Мера | Эффект |
|---|
| Сборка | Пользователь без прав root (UID 65532) | Процесс контейнера никогда не запускается от root |
| Сборка | -s -w ldflags + auto -trimpath | Удалённый бинарный файл, нет утечки локальных путей |
| Сборка | Только 3 пакета | Минимальная поверхность атаки, нет оболочки и менеджера пакетов |
| Выполнение | --read-only | Неизменяемая корневая файловая система |
| Выполнение | --cap-drop=ALL | Нулевые возможности Linux |
| Выполнение | --no-new-privileges | Предотвращает повышение привилегий через setuid/setgid |
| Команда | Результат |
|---|
docker compose run --rm melange keygen keys/melange.rsa | Пройдено |
docker compose run --rm melange build melange/dasel.yaml --arch x86_64 --signing-key keys/melange.rsa | Пройдено — патч применён (7/7 фрагментов), APK создан |
docker compose run --rm melange test melange/dasel.yaml --arch x86_64 | Пройдено — версия, извлечение ключа JSON, доступ к массиву JSON |
docker compose run --rm apko build apko/dasel.yaml dasel:3.3.1 dasel.tar --arch x86_64 --sbom-path sbom/ | Пройдено — установлено 3 пакета, OCI-тарбол создан |
docker load --input dasel.tar | Пройдено — dasel:3.3.1-amd64 загружен |
bash tests/test.sh | Пройдено — все тесты (версия, извлечение ключа, преобразование форматов, алиасы YAML, патч CVE) |
docker run --rm -v ... anchore/grype:latest /work/dasel.tar | Пройдено — 1 находка (ожидаемый ложноположительный результат для исправленного CVE) |
docker run --rm -v ... anchore/syft:latest /work/dasel.tar | Пройдено — каталогизировано 36 пакетов (3 APK + 32 Go + 1 stdlib) |