landing · Сайты 24 26.1100.0 Безопасность

Landing 26.1100.0: закрыта цепочка уязвимостей, заодно ужесточены repo.register, savePicture и проверка ссылок предпросмотра

14 мин чтения Устаревших API: 4

Обновление безопасности

Закрыта уязвимость или ослабленная проверка прав. Ставить в первую очередь.

landing 26.1100.0 (сборка от 06.08.2026) почти целиком про безопасность. Закрыты исполнение кода через манифест repo-блока и импорт архива сайта, инъекция в eval() через CODE страницы, SSRF через обработчик виджета, XSS в выводе ассетов, предсказуемый в облаке md5-хеш предпросмотра. В комментариях ядра прямо названы тикеты Mantis #252937, 253773 и 253734. Попутно изменилось поведение публичных API. Сильнее всего это заденет тех, кто регистрирует блоки через REST, зовёт Manager::savePicture() с путём на диске или раздаёт ссылки на предпросмотр неопубликованного сайта.

Дифф на 1029 файлов, +29899/−19034 строк. Около 380 записей приходится на lang-файлы, ещё 240 на пересобранные бандлы. Схема БД не менялась.

Проверьте приложения, которые регистрируют блоки через landing.repo.register

Метод Bitrix\Landing\PublicAction\Repo::register() раньше проверял меньше. Теперь правила такие:

Кто может вызывать. Появилась проверка checkRepositoryAccess(): писать в репозиторий может REST-приложение (есть $app['CODE']) или администратор (Rights::isAdmin()). Остальные получают ошибку ACCESS_DENIED. То же самое для unregister.

Чей блок найдётся. Фильтр поиска записи теперь всегда ['=XML_ID' => ..., '=APP_CODE' => $app['CODE'] ?? false]. Вызов без контекста приложения больше не найдёт и не перезапишет блок чужого приложения с тем же XML_ID. Если вы так обновляли блоки админским скриптом, теперь появится дубль, а существующая запись не обновится.

Что сохранится. Поля и манифест проходят через новый allow-list Security\RepoNormalizer::normalize():

  • неизвестные ключи полей и манифеста отбрасываются молча, без ошибки;
  • у путей в assets.css и assets.js проверяются расширение, схема (только http/https) и запрещённые символы.

assets.class и callbacks метод register вырезал и раньше: первый в onRegisterCheckManifest(), второй в onRegisterBefore(). Для REST новое только allow-list остальных ключей и проверка путей ассетов.

Приложение отправило манифест, REST ответил успехом, а блок ведёт себя иначе, потому что часть манифеста до базы не дошла. Ошибки вы не увидите, придётся сравнивать отправленное с сохранённым.

Виджеты отдельно. Подтип widgetvue в manifest.block.subtype добавлен в запрещённые для обычного register, рядом с widget. Такой вызов вернёт ошибку UNSUPPORTED_BLOCK_SUBTYPE (по коду 26.1100.0). Виджет регистрируется только через RepoWidget::register().

Наследникам. Удалён protected static Repo::onRegisterCheckManifest(array &$manifest). Переопределение этого хука в своём классе больше не вызывается, а обращение parent::onRegisterCheckManifest() закончится фаталом.

Блоки из репозитория больше не исполняют код из манифеста

Раньше Block::getAsset() превращал assets.class в путь для include php-файла, а Block::createFromRepository() вызывал callbacks.afteradd. REST-метод register эти ключи вырезал, но в b_landing_repo блок попадает и в обход него: через импорт архива сайта, прямой вызов Landing\Repo::add(), плюс там лежат старые записи. По комментарию в RepoNormalizer, любое из этих значений в базе означало исполнение произвольного кода на портале.

Теперь callbacks.afteradd вызывается только через новый Block::executeAfterAddCallback(). Для repo-блока колбэк сработает, только если это \Closure. В Block::getAsset() у repo-блока читаются лишь ключи css, js, ext. Тот же вызов подставлен в PublicAction\AiBlock.

Если ваш модуль клал afteradd или assets.class через Landing\Repo::add() или импорт, колбэк перестанет срабатывать, а php-файл из assets.class больше не подключится. Ошибок в логах не будет.

Импорт архива сайта тоже шёл мимо санитайзера: Transfer\Script\Action\Closet\BlockTrait клал repo_info в Repo::add() как есть. Теперь данные проходят через RepoNormalizer. Отклонённый контент при этом не выбрасывается, а сохраняется очищенным.

Repo::bind: без REST-приложения привязка не сработает

Repo::bind() теперь требует контекст REST-приложения и установленный модуль rest. Без них вернётся ACCESS_DENIED. Дополнительные проверки:

  • код размещения обязан начинаться с LANDING_, иначе PLACEMENT_UNKNOWN;
  • обработчик проверяется через \Bitrix\Rest\HandlerHelper::checkCallback(), при неудаче PLACEMENT_HANDLER_INVALID;
  • APP_ID берётся только из приложения, значение из входных полей игнорируется;
  • в PlacementTable пишется USER_ID = PlacementTable::DEFAULT_USER_ID_VALUE.

RepoWidget::register: обработчик виджета на локальном адресе больше не пройдёт

WIDGET_PARAMS.handler проверяется через Sanitizer::sanitizeWidgetHandlerUrl(). Принимается только абсолютный http(s)-URL. Хост не может быть приватным, loopback или зарезервированным IP, не может быть и «числовой» записью адреса. Протокол https обязателен для нового виджета и при смене обработчика, http остаётся только у неизменённого обработчика. Ошибка в REST-ответе — WIDGET_HANDLER_INVALID.

Больше всего это заденет dev-стенды. Виджет с обработчиком на http://192.168.x.x/... или http://127.0.0.1/... зарегистрировать не получится. Уже зарегистрированные виджеты с приватным адресом тоже перестанут работать, потому что Controller\Vibe проверяет адрес при каждом запросе к обработчику и отвечает ошибкой HANDLER_ADDRESS_NOT_ALLOWED.

Причина — SSRF. Controller\Vibe раньше делал (new HttpClient())->post($url, $params) по URL из манифеста без каких-либо проверок. В Sanitizer::isUnsafeAddressHost() отдельно отсекаются записи вида 127.1, 2130706433, 0177.0.0.1, 0x7f.0.0.1. Рядом комментарий: ctype в PHP облака не встроен, а pcre есть всегда, поэтому проверки написаны на регулярках.

Manager::savePicture с путём на диске теперь вернёт false

У Manager::savePicture() появился четвёртый параметр и изменилось поведение:

        public static function savePicture($file, $ext = false, $params = array(), bool $trustedSource = false)

    

Без $trustedSource = true:

  • локальный путь (/upload/...) даёт false;
  • файловый массив обязан пройти is_uploaded_file(). Массив, собранный руками через CFile::MakeFileArray(), не подойдёт: метод вернёт false и запишет в журнал событий LANDING_FILE_UNTRUSTED_SOURCE с ключами массива.

Расширение сверяется со списком изображений при любом значении флага, но только для base64-массива [имя, данные].

Комментарий в ядре говорит, что ветка локального пути оставлена для обратной совместимости с вызовами вне монорепозитория. Но без флага она не работает. Фатала и исключения нет. Для локального пути метод тихо вернёт false, для массива оставит ещё и запись в журнале. Если результат у вас не проверялся, картинка у блока не появится.

Было и стало:

        use Bitrix\Landing\Manager;

// До 26.1100.0 работало, теперь вернёт false
$picture = Manager::savePicture('/upload/import/hero.jpg');

// Путь сформирован вашим кодом, а не пришёл от пользователя
$picture = Manager::savePicture(
    '/upload/import/hero.jpg',
    false,
    [],
    trustedSource: true,
);

if ($picture === false)
{
    $logger->warning('Landing: не удалось сохранить картинку', ['path' => '/upload/import/hero.jpg']);
}

    

Ставьте trustedSource: true только там, где путь целиком формирует ваш код. Если в путь попадает что-то из запроса, с этим флагом вы заново откроете закрытую уязвимость.

Все выданные ссылки предпросмотра умрут

Site::getPublicHash() раньше считал md5() в облаке от хоста и пути публикации, в коробке от домена, ID сайта и лицензионного ключа. Облачный хеш можно было предсказать. Теперь это подпись Bitrix\Main\Security\Sign\Signer с солью landing_public_hash. Сравнение идёт через новый Site::isPublicHashValid() на hash_equals, он же подставлен в компонент landing.pub.

Все ранее выданные ссылки на предпросмотр неопубликованного сайта после обновления перестанут открываться. Заказчикам, которым вы отправляли такие ссылки на согласование, придётся разослать новые. В своём коде, где хеш сравнивался вручную, переходите на штатную проверку:

        use Bitrix\Landing\Site;

$hash = (string)$request->get('hash');

if (!Site::isPublicHashValid($siteId, $hash))
{
    return null;
}

    

CODE страницы, сайта и папки: часть символов под запретом

В onBefore*-проверки LandingTable, SiteTable и FolderTable добавлен Security\SyspageUrl::isSafeCode(). Запрещены символы ' " ` $ \ < > ( ) { } и управляющие байты. При нарушении add()/update() вернёт неуспешный результат с кодом WRONG_CODE_CHARS.

URL системных страниц #system_* подставляются в контент блока, а контент исполняется через eval() в Block::view(). Это тикет Mantis #253773, инъекция через CODE.

Тексты ошибок захардкожены по-английски, без Loc, и пользователь русского портала увидит английскую фразу. Импортёры, которые генерируют CODE из заголовков, лучше прогонять через ту же проверку заранее:

        use Bitrix\Landing\Security\SyspageUrl;
use Bitrix\Main\Error;
use Bitrix\Main\Result;

$result = new Result();

if (!SyspageUrl::isSafeCode($code))
{
    $result->addError(new Error('Недопустимые символы в коде страницы', 'WRONG_CODE_CHARS'));

    return $result;
}

    

Site::updateFolder и перенос папок между сайтами

Site::updateFolder() получил новые проверки:

  • папка и PARENT_ID должны принадлежать сайту;
  • вложить папку в саму себя или в своего потомка нельзя (MOVE_RESTRICTION);
  • INDEX_ID должен быть страницей этого же сайта (FOLDER_INDEX_OUT_OF_SITE).

Кроме того, FolderTable при смене SITE_ID у существующей папки требует право delete на старом сайте и edit на новом. Скрипты, переносившие папки обычным update с новым SITE_ID, начнут получать отказы.

Шлюз PublicAction: лимит batch и общая фраза вместо текста исключения

В PublicAction, через который идут AJAX и REST, изменились три вещи.

  • В AJAX-batch редактора (PublicAction::ajaxProcessing()) можно передать не больше 500 команд (MAX_BATCH_ITEMS), дальше ошибка BATCH_LIMIT_EXCEEDED. Загрузка файлов внутри такого batch запрещена: BATCH_FILES_NOT_ALLOWED. По 100 команд режет только новый BX.Landing.Backend.batchList() (BATCH_ITEMS_PER_REQUEST), и вызывает его пока лишь getLandings(). Обычный batch() ничего не режет, так что свой вызов batch() на 500+ команд получит BATCH_LIMIT_EXCEEDED. REST-вызовы через restGateway() эту проверку не проходят.
  • Scope команды больше не наследуется от соседней команды в batch. Если у команды scope не указан, вызывается Type::clearScope(). В AJAX-шлюзе командам без своего scope подставляется общий type запроса (getBaselineScope()). Кто рассчитывал, что первая команда «включит» scope для остальных, должен указывать его в каждой команде (в AJAX хватит общего type).
  • Текст исключения действия отдаётся клиенту только при включённом exception_handling.debug. Иначе приходит общая фраза, а детали пишутся в журнал событий с типом LANDING_ACTION_EXCEPTION и троттлингом 600 секунд. При отладке интеграции сообщение об ошибке теперь надо искать в журнале событий, в ответе его не будет.

Method-static кеши прав в Rights::hasAccessForSite/hasAccessForLanding, Role, LandingTable, SiteTable «протекали» между командами batch. Scope переключается покомандно внутри одного PHP-процесса, и первая команда фиксировала роли для всех следующих. Кеши переведены на ключ по scope или убраны. Агенты в lib/agent.php теперь сохраняют и восстанавливают scope и глобальный флаг прав вызывающего.

Остальные ломающие изменения

  • PublicAction\Domain::check() — клиентский $filter урезан до ключей ID, =ID, !ID, !=ID с целочисленными значениями. В комментарии объяснение: через dot-нотацию ORM получался оракул по чужим таблицам. Остальные ключи фильтра игнорируются.
  • Site\Type::getScopeClass() — класс scope берётся из закрытого списка SCOPE_CLASSES (GROUP, KNOWLEDGE, VIBE), а не склейкой пользовательского ввода с namespace. Приватный getFullScopeClass() удалён. Свой класс, подложенный в Bitrix\Landing\Site\Scope\*, больше не подхватится.
  • Controller\Landing — переопределение configureActions() убрано, метод теперь наследуется от Main\Engine\Controller. С getByIdAction снят префильтр ActionFilter\Extranet, потому что базы знаний групп открыты экстранет-пользователям. Controller\Tailwind, наоборот, теперь берёт ...parent::getDefaultPreFilters() и требует POST для saveCss. Базовый Controller включает Authentication, HttpMethod и Csrf (по коду 26.1100.0), так что к saveCss перестанут проходить и GET-запросы, и запросы без sessid.
  • Node\StyleImg::getNode(Block $block, $selector, ?array $preloadedFiles = null) — добавлен необязательный параметр. Заденет только наследников с переопределённым методом: получат фатал о несовместимой сигнатуре.
  • Copilot — в интерфейс Copilot\Generation\Scenario\IScenario добавлены isAnalyticStartEnabled() и onGenerationError(Generation, GenerationException). Фатал о нереализованных абстрактных методах получат только классы, которые реализуют IScenario напрямую. У наследников BaseScenario для обоих методов есть реализации по умолчанию. Удалены Integration\AiAssistant\WidgetBotResolver и WidgetDataProvider::getAiAssistantBotId().
  • Роли в scope — PublicAction\Role проверяет checkScope($id): роль чужого scope нельзя ни прочитать, ни изменить. Переключение режима прав доступно только при Rights::canSwitchMode() (вне scope или админу).
  • Rights::ADDITIONAL_RIGHTS — ключ mainpage_create заменён на vibe_create, vibe_admin, vibe_menu24. Первые два без явной настройки запрещены (DENIED_WHEN_UNCONFIGURED). Код, который читает Rights::ADDITIONAL_RIGHTS['mainpage_create'], получит предупреждение Undefined array key и null вместо кода права.
  • Удалён шаблон .default компонента landing.site_copilot (остался только ai) и JS-расширение landing.animation.copilot целиком. Если вы копировали шаблон .default к себе или подключали это расширение, проверьте.

Deprecated

Новых @deprecated в релизе нет. Всё удалённое удалено сразу, без переходного периода.

Новое: namespace Security и пачка санитайзеров

RepoNormalizer — тот же allow-list, что применяет ядро

Bitrix\Landing\Security\RepoNormalizer::normalize() — единая нормализация блока репозитория для REST и импорта. Возвращает DTO NormalizedRepoBlock с двумя публичными свойствами: fields и contentRejected. Через него можно заранее проверить, что ядро сделает с вашими полями и манифестом. Манифест лежит в fields['MANIFEST'] уже сериализованным, в том виде, в каком попадёт в b_landing_repo, поэтому для сравнения его придётся развернуть:

        use Bitrix\Landing\Security\RepoNormalizer;

$normalized = RepoNormalizer::normalize(
    fields: $fields,
    manifest: $manifest,
    xmlId: 'acme.hero_banner',
    appCode: 'acme.landing_blocks',
);

$storedManifest = unserialize($normalized->fields['MANIFEST'], ['allowed_classes' => false]);

if ($normalized->contentRejected)
{
    // register вернёт CONTENT_IS_BAD/PRESET_CONTENT_IS_BAD и ничего не сохранит
    $logger->error('Контент repo-блока не прошёл санитайзер', ['xmlId' => 'acme.hero_banner']);

    return;
}

$dropped = array_filter([
    'fields' => array_keys(array_diff_key($fields, $normalized->fields)),
    'manifest' => array_keys(array_diff_key($manifest, $storedManifest)),
    'manifest.block' => array_keys(array_diff_key($manifest['block'] ?? [], $storedManifest['block'] ?? [])),
]);
$assetsChanged = ($manifest['assets'] ?? []) != ($storedManifest['assets'] ?? []);

if ($dropped !== [] || $assetsChanged)
{
    $logger->notice('Repo-блок будет сохранён не целиком', [
        'dropped' => $dropped,
        'assetsChanged' => $assetsChanged,
    ]);
}

    

Флаг contentRejected по-разному влияет на два входа. REST register при нём ничего не сохраняет и возвращает CONTENT_IS_BAD или PRESET_CONTENT_IS_BAD, а импорт сохраняет очищенный контент.

Sanitizer: проверка URL обработчика и CSS-ссылок

В Bitrix\Landing\Sanitizer появились sanitizeWidgetHandlerUrl(string $url, bool $requireHttps = false) и sanitizeCssUrl(string $url). hasDisallowedScheme() стал public static. Ещё добавлено восстановление тега <style>, разрезанного аудитором.

        use Bitrix\Landing\Sanitizer;
use Bitrix\Main\Error;
use Bitrix\Main\Result;

$result = new Result();
$handlerUrl = Sanitizer::sanitizeWidgetHandlerUrl($handler, requireHttps: true);

if ($handlerUrl === '')
{
    $result->addError(new Error('Обработчик виджета должен быть публичным https-адресом', 'WIDGET_HANDLER_INVALID'));

    return $result;
}

    

Этим можно проверить обработчик у себя до отправки в RepoWidget::register(), чтобы не ловить WIDGET_HANDLER_INVALID на стороне портала.

Что ещё появилось

  • Security\SyspageUrl::isSafeCode() / sanitize() — защита URL системных страниц #system_*.
  • AI\SiteBuilder\Html\AiBlockHtmlSanitizer::sanitize(string $html) — allow-list-санитайзер разметки AI-блоков на Bitrix\Main\Web\DOM с пересериализацией дерева.
  • Хуки страниц — Hook\Page\CssBlock::escapeCssForStyleTag() экранирует </style как \3c /style. Добавлены Hook\Page\ThemeFonts::sanitizeFontName() и Hook\Page\Cookies::sanitizeColor().
  • Controller\Vibe::requestWidgetHandler() / createHandlerHttpClient() — запрос к обработчику виджета вынесен в отдельный метод: проверка URL, таймаут 5 секунд, лимит тела 1 МБ, отдельная обработка кодов PRIVATE_IP, URI_SCHEME, URI_HOST, URI_PUNICODE. auth больше не подмешивается в исходные $params.
  • Права — Rights::canSwitchMode(), isGlobalOn(), isRightInScope(), hasCodeInScope(), isExtendedGrantAcceptable(), reset*Cache(). Role::clearCache(), clearRolesCache(), isInCurrentScope(). RoleTable::onAfterAdd/onAfterUpdate сбрасывают кеши. Плюс Site\Type::isScopeEntered() и Site\Scope\Vibe::getOperationsForSite().
  • Vibe — Vibe\Vibe::canCreate() и AbstractVibeProvider::canCreate()/hasExplicitVibeRight(): создание главной страницы по явно выданному праву плюс проверка тарифной фичи.
  • Copilot: правка выбранного элемента AI-сайта — сценарий ChangeAiSiteSelectedElement был ещё в 26.1000.0, теперь в его карте шагов появились TaskResolveChangeAiSiteSelectedElement и RequestChangeAiSiteSelectedElementBlockHtml. На фронте — TypeScript-расширение landing.copilot.element-picker. Фича спрятана за опцией landing_ai_site_selected_element_enabled, по умолчанию N.
  • Copilot, остальное — шаг TaskFinishCreateAiSite завершает сценарий CreateAiSite. Хелпер ChangeAiSiteStructuralDiff ловит структурную регрессию HTML в RequestImproveChangeAiSiteBlockHtml. GenerationErrorStatusMapper переводит ошибку генерации в статус аналитики, его вызывают Generation и сценарий ChangeAiSite. AdditiveNodeTagger в TaskPrepareChangeAiSiteBlocksMarkup восстанавливает коды ai-node-*, которые модель потеряла при переписывании блока.
  • Метрика — Metrika\BlockContentChangeDetector, BlockEditMetrikaSender (sendManualEdit/sendAiEdit), BlockContentKinds, EditorOpenEventResolver, PublicationErrorStatusMapper, SiteTypeResolver, а также Landing::getSiteTypeCode(). Это аналитика ручных и AI-правок блоков из PublicAction\Block.
  • По мелочи: Agent::isFolderStorageAvailable(), Copilot\Generation::existsBySiteId()/isFinishedPersisted(), PublicAction::getBaselineScope()/writeExceptionToLog().

БД

Схема не менялась. Новый степпер Bitrix\Landing\Update\Repo\ContentSanitizer в два этапа по 200 строк вычищает уже сохранённые манифесты и контент: сначала b_landing_repo, затем экземпляры repo_% в b_landing_block. Переписываются только реально изменившиеся строки.

В самом диффе привязки степпера нет, класс только объявлен. По диффу не видно, запускается ли он автоматически при установке обновления. Поэтому не рассчитывайте, что старые записи в репозитории уже очищены.

Мелочи и находки

  • XSS в выводе ассетов. Assets\Manager подставлял путь ассета в <link href> и <script src> без экранирования, теперь там htmlspecialcharsbx($path, ENT_QUOTES). В шаблонах компонентов экранирование добавляли массово. В диффе 204 добавленные строки с htmlspecialcharsbx|CUtil::JSEscape|Json::encode против 43 удалённых. Например, CUtil::JSEscape получил TPL_CODE в шаблоне .default компонента landing.mainpage.pub, а в component_epilog.php у landing.pub теперь экранируются превью страницы, meta Bitrix24SiteType и путь к favicon.
  • Промпт модерации лежит в модуле. В lib/AI/SiteBuilder/Prompt/ai-moderate-topic.md положен текст промпта модерации тематики AI-сайта (код landing_ai_site_moderation). В пометке сказано, что в рантайме он читается из b_ai_prompt, а файл служит «source of truth» и фикстурой для ModerationPromptContractTest. Внутри осталась внутренняя инструкция деплоя: загрузить тело шаблона на каждый целевой портал.
  • Аналитика шагов Copilot. У девяти шагов Copilot\Generation\Step\* убраны переопределения getAnalyticEvent(), для них метод теперь возвращает null из BaseStep. Вызов не упадёт, сам метод объявлен в Step\Base\IStep.
  • Многооконный редактор и instanceof Blob. File из другого окна не проходил instanceof Blob. В imagecompressor появились is-blob.js, который узнаёт Blob и File любого окна по Object.prototype.toString, и to-current-window-blob.js с clone-blob.js, которые пересобирают такой объект конструкторами текущего окна. В imageuploader добавлен clone-file.js: он делает отдельную копию файла для каждого запрошенного размера, потому что имя для загрузки задаётся на самом объекте и общий файл переименовывался бы по разу на каждый размер.

Что делать

  1. Обновляйтесь не откладывая и сразу до 26.1100.200. Закрытые дыры серьёзные, а их механика теперь описана прямо в комментариях ядра. В самом 26.1100.0 Controller\DiskFile всё ещё вызывает Block::isContains(), удалённый в 26.1000.0, поэтому скачивание и просмотр файлов Диска из блоков не работают (по коду 26.1100.0). В 26.1100.200 это исправлено, подробности в разборе 26.1100.200.
  2. Сделайте grep по своему коду:
    • savePicture( — где передаётся путь на диске или массив не из $_FILES, добавьте trustedSource: true и проверку результата на false;
    • getPublicHash — ручное сравнение хеша замените на Site::isPublicHashValid();
    • onRegisterCheckManifest, WidgetBotResolver, getAiAssistantBotId — этих символов больше нет;
    • mainpage_create — ключа в Rights::ADDITIONAL_RIGHTS больше нет, права теперь vibe_create, vibe_admin, vibe_menu24;
    • implements IScenario — допишите два новых метода;
    • landing.animation.copilot и шаблон .default у landing.site_copilot — удалены.
  3. Если у вас REST-приложение с блоками, прогоните манифесты через RepoNormalizer::normalize() на тестовом портале и посмотрите, что отбрасывается. Для блоков, которые попадают в репозиторий через Landing\Repo::add() или импорт, на assets.class и callbacks больше не рассчитывайте. Виджеты регистрируйте через RepoWidget::register(), обработчик должен быть на публичном https-адресе.
  4. Placement'ы привязывайте только из контекста приложения, код размещения начинайте с LANDING_.
  5. Перевыпустите ссылки предпросмотра неопубликованных сайтов, которые уже отправили заказчикам.
  6. В импортёрах страниц проверяйте CODE через SyspageUrl::isSafeCode() до сохранения и обрабатывайте WRONG_CODE_CHARS.
  7. В AJAX-batch редактора держите не больше 500 команд и не отправляйте в нём файлы. scope указывайте в каждой команде, где он нужен (в AJAX хватит общего type).
  8. Когда интеграция отвечает общей фразой вместо внятной ошибки, ищите детали в журнале событий по типу LANDING_ACTION_EXCEPTION.

Устаревшие и удалённые API в этой версии

Символ Статус Чем заменять
Bitrix\Landing\PublicAction\Repo::onRegisterCheckManifest() Удалено Bitrix\Landing\Security\RepoNormalizer::normalize()
Bitrix\Landing\Rights::ADDITIONAL_RIGHTS['mainpage_create'] Удалено Bitrix\Landing\Rights::ADDITIONAL_RIGHTS['vibe_create']
Bitrix\Landing\Integration\AiAssistant\WidgetBotResolver Удалено —
Bitrix\Landing\Integration\AiAssistant\WidgetDataProvider::getAiAssistantBotId() Удалено —

Читайте дальше

landing 26.1200.0 Безопасность Свежее

Landing 26.1200.0: подписанный предпросмотр ушёл в CSP-песочницу, а импорт с заменой сайта помечает старые страницы удалёнными

Landing 26.1200.0 трогает 690 файлов, но основная масса там картинки, переводы и пересобранные бандлы. Релиз закрывает дыры в подписанной ссылке предпросмотра, чинит импорт с заменой сайта и размечает для скринридеров интерфейсы прав, настроек и редактора. Если вы вызываете `AiSiteChatAvailabilitySe...

2 мин
landing 26.1100.200 Безопасность Свежее

Landing 26.1100.200: контроллер файлов Диска требует авторизацию и наконец отвязался от удалённого Block::isContains

Контроллер `Bitrix\Landing\Controller\DiskFile`, через который блоки Сайтов отдают файлы Диска, получил префильтры и проверку права на чтение страницы. Заодно он перестал вызывать `Block::isContains()`, который удалили ещё в 26.1000.0. Публичные сигнатуры и БД не менялись.

3 мин
landing 26.1100.100 Рутинное Свежее

Landing 26.1100.100: только номер версии

В `install/version.php` поменялись номер версии и дата сборки (20 августа), больше в релизе ничего нет. Следом идёт [landing 26.1100.200](/bitrix-updates/landing/landing-26-1100-200) с содержательной правкой контроллера файлов Диска.

1 мин
landing 26.1000.0 Заметное

Landing 26.1000.0: удалён Block::isContains, ссылки теперь режутся по белому списку схем

Обновление `landing` 26.1000.0 (сборка от 24.08.2026) — это на 90% security-хардening плюс новая песочница для превью страниц «на устройствах». Дифф огромный — 1300 файлов, +73 тысячи строк — но почти всё это пересобранные JS-бандлы, контентные блоки и webp вместо png. Содержательного PHP — примерно...

4 мин
Мы используем файлы cookie для улучшения работы сайта. Продолжая использовать сайт, вы соглашаетесь с нашей политикой конфиденциальности.
AI Домовой

AI Домовой История

на связи

пишет…
Нет истории чатов
AI Домовой

Нужна авторизация

Войдите, чтобы задавать вопросы AI Домовому.

Войти