Skip to content
KitploitKITPLOIT
ИнструментыБлог
Отправить
ИнструментыБлог
Отправить

Инструменты для хакинга, пентеста и кибербезопасности — ваш арсенал защиты!

Kitploit — это каталог инструментов для хакинга, кибербезопасности и пентестинга. Находите последние обновления проектов для поиска уязвимостей, анализа систем, автоматизации тестирования и усиления вашей безопасности.

··Ленты·Контакты·Конфиденциальность·© 2026 Kitploit

Каталог инструментов

Категории

Все категории
Loading categories
openlore-PoC — PoC — обход пути через несанитизированное поле домена, полученное от LLM, в OpenLore (GHSA-5j8x-q7q6-58j5, CVE-2026-87001, CVSS 4.7). | Kitploit
Инструменты/GitHubGitHub/squeeze440/openlore-poc
Анализ уязвимостейАнализ КодаЭксплуатацияЭксплуатация веб-приложенийТестирование на ПроникновениеСтатьи и Исследования
GitHubsqueeze440/openlore-poc

openlore-PoC

PoC — обход пути через несанитизированное поле домена, полученное от LLM, в OpenLore (GHSA-5j8x-q7q6-58j5, CVE-2026-87001, CVSS 4.7).

Репозиторий
7 дней назадЕщё не проверено

Популярное

Смотреть все →

Откройте для себя самые используемые инструменты нашего сообщества.

Изучить все инструменты

Просмотрите нашу коллекцию инструментов

Смотреть все инструменты →
Поделиться

Обход пути в генераторе спецификаций OpenLore через несанитизированное поле domain, полученное от LLM

Статус CVE: запрошен, ожидает присвоения. Данная уязвимость опубликована как GHSA-5j8x-q7q6-58j5. После присвоения CVE этот репозиторий будет переименован в CVE-YYYY-NNNNN-openlore-PoC, а этот баннер заменён ссылкой на CVE.

ИсследовательDostxodjayev Abdullox (@squeeze440)
AdvisoryGHSA-5j8x-q7q6-58j5
CVSS 3.14.7 (Medium)
СлабостьCWE-22, CWE-73

Обход пути в генераторе спецификаций OpenLore через несанитизированное поле domain, полученное от LLM

Краткое описание: Злоумышленник, контролирующий содержимое репозитория, анализируемого командой openlore generate, может заставить конвейер генерации спецификаций OpenSpec записать Markdown-файл с подконтрольным злоумышленнику содержимым по произвольному пути в файловой системе за пределами целевого проекта, поскольку значение domain, возвращаемое вызовом извлечения LLM на этапе Stage-3, используется дословно для построения выходного пути спецификации без санитизации обхода пути и без проверки ограничения перед fs.writeFile.

Продукт

OpenLore (clay-good/OpenLore), npm-пакет openlore, конвейер генерации спецификаций (openlore generate / генератор и записывающее устройство формата OpenSpec). Это не детерминированный путь analyze/orient/MCP guardrail — это единственный путь в коде проекта, который намеренно включает LLM в цикл генерации, согласно собственному README/спецификации проекта («LLM используется только там, где генерация неизбежна (написание спецификаций), и никогда в пути извлечения или guardrail»).

Протестированная версия

Git-коммит 1f2de00dfe75530efb256320c374dce36607ee70 (2026-07-31), версия package.json 2.1.7.

Оценка CVSS v3.1

4.7 (Medium) — CVSS:3.1/AV:L/AC:H/PR:N/UI:R/S:U/C:N/I:H/A:N

  • AV:L — триггером является локальный вызов CLI (openlore generate) для каталога на диске, а не сетевой сервис.
  • AC:H — эксплуатация требует, чтобы оператор запустил команду generate с поддержкой LLM (а не стандартный путь guardrail) с настроенным провайдером, и чтобы косвенная инъекция промпта в анализируемом репозитории действительно заставила модель выдать строку обхода пути в поле domain — условие, на которое злоумышленник влияет, но не контролирует полностью.
  • UI:R — оператор должен выбрать запуск генерации спецификаций для вредоносного репозитория.
  • I:H / C:N / A:N — ошибка представляет собой примитив записи с частично подконтрольным злоумышленнику содержимым, попадающим по выбранному злоумышленником пути за пределами проекта; не было продемонстрировано чтение конфиденциальных данных или надёжное снижение доступности, поэтому эти метрики консервативно установлены в N.

Детали

ExtractedService.domain (src/types/pipeline.ts:105) заполняется напрямую из вызова LLM на этапе Stage 3, которому передаётся необработанное содержимое файлов анализируемого репозитория и который должен вернуть JSON-массив сервисов:

  • src/core/generator/stages/stage3-services.ts:45-52 строит промпт из fileChunks[i] (буквальный исходный текст анализируемого репозитория) и вызывает pipeline.llm.completeJSON<ExtractedService[]>(..., STAGE3_SERVICE_SCHEMA).
  • src/core/generator/schemas.ts:100 — STAGE3_SERVICE_SCHEMA.items.properties.domain имеет вид { type: 'string' }: без pattern, без enum, без allowlist. Любая строка, возвращённая моделью, принимается.
  • src/core/generator/openspec-format-generator.ts:161 — const domainName = service.domain || this.inferDomain(...) использует эту строку как есть.
  • src/core/generator/openspec-format-generator.ts:563 — path: \openspec/specs/${domain.name.toLowerCase()}/spec.md`интерполирует её напрямую в объявленный выходной путь спецификации. Обратите внимание, чтоnormalizeDomainName() (src/core/generator/openspec-compat.ts:655) существует в графе зависимостей того же файла и применяется в других местах (src/core/generator/openspec-writer.ts:167`, для сравнения устаревших каталогов доменов) — но он никогда не вызывается здесь, в единственном месте, где значение фактически становится путём в файловой системе.
  • src/core/generator/openspec-writer.ts:248 — const fullPath = join(this.rootPath, spec.path); использует обычный node:path.join, который лексически разрешает сегменты ../, без вызова собственного safeJoin() проекта (src/utils/path-confinement.ts), через который, согласно openspec/specs/mcp-security/spec.md, обязана проходить любая другая поверхность с недоверенными путями в этой кодовой базе (обработчики MCP, /api/skeleton и /api/spec-requirements в openlore view).
  • src/core/generator/openspec-writer.ts:277 / :294 затем выполняет writeFile(fullPath, spec.content, 'utf-8'), а ensureDir() (openspec-writer.ts:497-499) выполняет mkdir(dirname(filePath), { recursive: true }) для того же неограниченного пути, создавая любые отсутствующие промежуточные каталоги на пути за пределы корня проекта.

Итоговый эффект: значение domain, такое как ../../../../../../tmp/x, без изменений проходит от JSON-ответа LLM до реального вызова writeFile, оказываясь полностью за пределами анализируемого проекта. Это в точности та модель угроз «содержимое репозитория перенаправляет запись за пределы корня проекта», которую собственный openspec/specs/mcp-security/spec.md проекта явно определяет и защищает на поверхностях MCP/serve/view (safeJoin, учитывающее симлинки ограничение, гейт покрытия параметров пути) — поверхность генератора/записывающего устройства просто не имеет эквивалентного гейта.

Доказательство концепции

Живой вызов LLM не производился (соблюдение моделью инъецированной инструкции вероятностно и не является интересной частью этой ошибки); вместо этого PoC вызывает реальные, немодифицированные OpenSpecFormatGenerator и OpenSpecWriter из OpenLore с PipelineResult, единственное поле ExtractedService.domain которого содержит ровно ту форму строки, которую STAGE3_SERVICE_SCHEMA сегодня позволяет вернуть LLM, и ровно то, что комментарий в исходном файле с инструкцией «установить domain в ../../../.../tmp/x» мог бы вызвать на этапе Stage 3 (который передаёт модели необработанное содержимое файлов).

Скрипт: ~/engagements/openlore/source/poc-domain-traversal.ts (корень репозитория протестированного клона), запускается против временного проекта в ~/engagements/openlore/evidence/victim-project:

root@kitploit:~
cd ~/engagements/openlore/source
npx tsx poc-domain-traversal.ts

Результат: OpenSpecFormatGenerator.generateSpecs() (немодифицированный) выдаёт спецификацию домена с path: "openspec/specs/../../../../../../../../../../../../../../../../../../../../tmp/openlore_traversal_proof/spec.md", и OpenSpecWriter.writeSpecs() (немодифицированный) записывает её — файл оказывается в /tmp/openlore_traversal_proof/spec.md, полностью за пределами корня victim-project, тогда как victim-project/openspec/specs/ всегда содержит только два легитимных каталога overview/architecture.

Скриншоты (подлинные снимки Xvfb+fluxbox+xterm, scrot -w <window id>):

  • ../evidence/poc-generator-write.png — запуск PoC: необработанный spec.path генератора, содержащий обход пути, строка лога записывающего устройства Wrote openspec/specs/../../.../tmp/openlore_traversal_proof/spec.md, и собственное подтверждение скрипта, что /tmp/openlore_traversal_proof/spec.md существует с подконтрольным злоумышленнику содержимым.
  • ../evidence/poc-outside-fs-proof.png — независимое подтверждение: ls для victim-project/openspec/specs/ показывает только architecture/overview (никаких следов вредоносного домена внутри проекта), тогда как ls -la /tmp/openlore_traversal_proof/ показывает сбежавший spec.md, лежащий непосредственно в /tmp.

Влияние

Злоумышленник, способный заставить цель запустить openlore generate (генерацию спецификаций с поддержкой LLM) для репозитория, который он создал — правдоподобный сценарий для CLI-инструмента, чья явная цель — быть нацеленным на сторонние/недоверенные кодовые базы — может записать файл с подконтрольным злоумышленнику содержимым по любому пути, доступному для записи пользователю ОС оператора, ограничиваясь лишь количеством сегментов ../, необходимых для выхода, и правами файловой системы. Запись не подтверждена как напрямую исполняемая, но достаточно неглубокий путь проекта мог бы позволить обходу достичь мест, которые исполняются или автоматически загружаются другими инструментами под той же учётной записью (файлы rc оболочки, пользовательские каталоги cron, конфигурации редактора/IDE), что не тестировалось и здесь не утверждается.

Слабости

  • CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')
  • CWE-73: External Control of File Name or Path
  • CWE-20: Improper Input Validation (первопричина — JSON-вывод LLM считается доверенным, как если бы он был сгенерирован внутренне)

Устранение

  1. Применить существующий normalizeDomainName() (или эквивалентное регулярное выражение allowlist, например ^[a-z][a-z0-9-]{0,63}$) к domain.name / service.domain в точке их первого принятия из ответа LLM (groupByDomain() в openspec-format-generator.ts), а не только на более позднем месте сравнения устаревших каталогов.
  2. Направить вычисление fullPath в OpenSpecWriter.writeSpec() через собственный safeJoin() проекта (src/utils/path-confinement.ts) вместо обычного node:path.join, в соответствии с ограничением, уже требуемым для любой другой поверхности с недоверенными путями в этой кодовой базе.
  3. Добавить ограничение pattern к STAGE3_SERVICE_SCHEMA.domain (и любому другому полю схемы, позже используемому для построения пути в файловой системе), чтобы провайдеры, применяющие схемы структурированного вывода, отвергали несоответствующие значения сразу.
  4. Добавить регрессионный тест — в духе существующего MCP «Path-Parameter Coverage Gate» — проверяющий, что GeneratedSpec.path, содержащий .. или разрешающийся за пределы rootPath, отвергается до того, как OpenSpecWriter обратится к файловой системе.

Благодарность

Dostxodjayev Abdullox

Канал отчётности

Для этого репозитория включено приватное сообщение об уязвимостях GitHub: https://github.com/clay-good/OpenLore/security/advisories/new (стандартный процесс GHSA). Подтверждено через gh api repos/clay-good/OpenLore/security-advisories, возвращающий [] (отсутствие предыдущих advisory) до этого аудита.

Скачать инструмент