Искусство. Код... ИИ?
598 subscribers
29 photos
4 videos
3 files
102 links
Канал о прекрасном и не очень, вокруг кода, искуственного интеллекта, и их безопасности.

Навигация по каналу: https://t.me/art_code_ai/105
Download Telegram
«Если тебе дадут линованную бумагу, пиши поперёк»


На днях, Денис Кораблев, с которым мне довелось классно проработать несколько лет, порассуждал на тему важности нарушения правил в инженерии (почитайте). И мне, как человеку, на которого эпиграф к «451° по Фаренгейту» оказал куда большее влияние, чем весь остальной роман, очень откликнулось.

Настолько, что позволю себе эту тему подхватить.

На моё отношение к инженерным исследованиям большое влияние в своё время оказали работы философа-логика Николаса Решера (очень рекомендую почитать хотя бы его «The Limits of Science» в последнем переиздании). Его взгляд на развитие науки — тема не на один пост, но одна его мысль перекликается со множеством работ других ученых, как более ранних, так и поздних:

Наука подобна исследованию «параметрического пространства» природы; ограниченность ресурсов (времени, денег, оборудования, талантов) вынуждает на развилках выбирать одно направление и безвозвратно терять другие.


У других авторов эта же мысль упоминается, как «зависимость путей», «эффект колеи», «QWERTY-эффект» и т.п. Но суть одна: в ходе любого исследования мы сталкиваемся с необходимостью принимать одну из возможных альтернатив, отбрасывая прочие из-за ограниченности ресурсов. И лишая себя возможности однажды к ним вернуться.

Совокупность причин, по которым на всём пути была выбрана та или иная альтернатива, по сути — формируют собой свод правил, определяющих дальнейшее движение, ту самую «колею». Согласитесь, было бы крайне нелогично на одной из развилок выбрать путь, соответствующий ресурсному критерию A, а каком-то из последующих — противоречащий ему? А критерии-то накапливаются...

И, с каждой развилкой, это все сильнее удаляет исследователя от возможности рассмотреть принципиально иные пути. Пути, которые возможно, в долгосрочной перспективе, привели бы к куда более эффективному решению, окажись на то у исследователя достаточно ресурсов.

К ходьбе по бездорожью, как и к прописи поперек линовки, можно относиться, как к нон-конформизму. В конце-концов, это он и есть. Но также это — единственный, на мой взгляд, способ сделать что-то по-настоящему значимое. Тот самый майндсет хакера, в олдскульном смысле — не удачно воткнуть кавычку в очередной плагин Wordpress'а, а шатать саму систему познания реальности везде, где это возможно (а где невозможно — шатать то, что этому мешает).

Уверен, что примерно это имел в виду и Денис. Мы сейчас находимся на одной из наиболее важных развилок, случавшихся за последние десятилетия развития вычислительных технологий. Выбрав правильный путь, можно здорово так продолжить текущую колею, делая её глубже, ровнее и эффективнее. Это очень круто, на самом деле. Но может, посмотреть на это иначе? Ведь сейчас у нас в распоряжении появился ресурс, которого не было на всех предыдущих развилках.

Может, стоит отойти немного назад, и хорошенько подумать, а не подходящий ли сейчас момент, чтобы двинуть по бездорожью?

#мысли_вслух
9💯6👍1
🖥 Какой может быть безопасная разработка Software 3.0?

Продолжаем рубрику «Фантазии вокруг постов коллег». Сегодня у нас на очереди серия публикаций Макса Митрофанова о будущем безопасной разработки и аппсека (рекомендую).

Начну с дополнения тезиса Макса о том, что (цитирую) «нельзя просто попросить codex/claude code сделать безопасно». Вообще-то, в целом можно, но только, если делать это с уважением правильно. Не «напиши мне безопасный код», конечно. «Правильно» — сводится к управлению фокусом внимания LLM, вокруг того, чем именно является в каждом конкретном проекте «безопасность». К контекст-менеджменту.

После публикации скилла-генератора SECURITY.md я очень много экспериментировал, пытаясь заставить LLM написать уязвимый код в проектах, для которых был построен этот файл. И... не смог. Нет, серьезно, если кто-то сможет — пришлите плс, какой был кейс, промпт, политика, агент и LLM, мне прям реально это нужно для тестов одной штуки.

Однако же, в целом согласен с тезисом про нынешнюю важность вендорских обвязок с высоким уровнем экспертности в безопасности. Но по другой причине — Swiss Cheese Model.

Идём дальше. С чем обычно ассоциируется термин AppSec в плане инструментов? SCA, SAST, DAST и AF, в первую очередь. И вот с их текущим state-of-the-art есть одна очень большая проблема. Думаю все согласятся с тем, что практика блэклистинга чего-либо, как способа обеспечения безопасности приложений, является анти-паттерном?

Тогда скажите на милость, почему буквально все существующие инструментальные средства аппсека работают именно по принципу черных списков? SCA ищет «плохие» зависимости, SAST ищет «плохие» фрагменты кода, DAST — определяет «плохое» поведение приложения, AF — фильтрует «плохие» запросы.

Понимаете? ВЕСЬ основной инструментарий аппсека сейчас основан на одном из самых заезженных ЕГО ЖЕ антипаттернов 🤷‍♂️

Безусловно можно (и нужно) усиливать текущие инструменты и подходы к аппсеку через ИИ там, где это имеет смысл. Все LLM-триажеры, агенты анализа кода, автопентестеры и т.п. — всё про это. Но такой аппсек, как был классическим, так и останется им же, лишь усиленным современными технологиями.

Но что, если ИИ даёт нам возможность пересмотреть взгляды на весь нынешний инструментарий? Что, если связка формального SAST и ИИ-агента (эдакий neuro-SAST), вместо поиска фрагментов уязвимого кода, будет доказывать их защищенность? А сработками будет то, защищенность чего не удалось доказать. SCA будет полагаться на эту связку, анализируя ей все зависимости. А DAST и AF — на построенный с помощью неё же поведенческий профиль приложения, описывающий то, что для приложения РАЗРЕШЕНО, а не запрещено.

В результате, вместо показательного аппсека, мы получим доказательный, гарантирующий, что отсутствие сработок — есть отсутствие уязвимостей. Аппсек без false negatives. Вот такое — уже вполне себе претендует на качественно новый уровень, как мне кажется.

Но можно пойти ещё дальше. Нет, буквально: если отойти по этой колее назад на достаточное расстояние (вспоминаем предыдущий пост), то станет понятно, что классический аппсек сформировался таким потому, что тогда, в истоках, просто не было другого выбора.

Но сейчас он — похоже, есть.

Одним из главных принципов нынешнего аппсека является shift-left — вынос влево по жизненному циклу приложения максимального количества усилий на обеспечение его безопасности. Но что, если мы будем применять описанный выше neuro-SAST, вкупе с грамотно построенными им же под конкретный проект политиками безопасности, не к уже написанному коду, а к... ещё не написанному? Сложно себе представить SAST, воткнутый на правах дискриминатора кода между полушариями мозга разработчика-человека. А вот разработчика-агента, раз уж теперь они пишут код — вообще не вопрос.

Как вам такой, доказательный леворадикальный аппсек?

Вот, что лично я вижу, как будущее безопасной разработки Software 3.0.

#мысли_вслух
Please open Telegram to view this post
VIEW IN TELEGRAM
5👍6🤔32🤯2
🤏 Зачем нужны скиллы для LLM, если модель и так всё знает?

То здесь, то там, можно встретить мнение, что скиллы, написанные с помощью LLM, бесполезны. Типа, раз модель смогла сгенерировать инструкцию, значит этот навык у неё и так был с момента обучения. Зачем тогда подсовывать ей инфу о том, что она и без того умеет?

LLM — это огромный набор весов, в которых после обучения лежит статистика связей между словами и понятиями. Там действительно есть примерно всё (ну... всё, на чем обучали модель). Так что первая часть рассуждения вполне справедлива: знания, которые описывает скилл, вероятнее всего, уже и так есть в параметрах модели. В этом плане ничего нового скилл в контекст не приносит.

На каждом шаге генерации модель смотрит не во все свои веса разом, а в текущий контекст — те токены, которые сейчас лежат в окне внимания. Так вот скилл нужен не для того, чтобы дать LLM новые знания, а чтобы в момент работы сфокусировать её внимание на конкретную часть весов. Это инструмент контекст-менеджмента, а не набор знаний, типа RAG. RAG подкидывает в контекст фактические данные, которых внутри модели может не быть. Скилл же — как бы поднимает приоритет уже существующих внутренних навыков. Что впрочем, никак не мешает ему и добавить модели знаний, если вдруг. Но всё же, по принципу работы, скилл ближе к условному few-shot, чем к RAG, являясь средством переориентации внимания, а не извлечения информации.

Отсюда следует ещё один неочевидный вывод. Скилл в принципе не обязан быть связным человеческим текстом. С точки зрения трансформера это просто токены, которые сдвигают вероятностное распределение в нужную сторону. Сгодятся списки, тезисы, схемы, обрывки кода, короткие маркеры и т.п. Связным русским или английским скилл пишут по другой причине: его потом проще вычитывать и править кожаным.

Так что генерировать скиллы LLM'кой можно и нужно, это банально быстрее. Но здесь всё то же, что и с gen-AI кодом: без ревью результаты могут неприятно удивить. Свежий обзор «Agent Skills for LLMs» прямо называет цифру: 26,1% скиллов из открытых сообществ содержат уязвимости — от утечек чувствительной инфы до некорректной обработки прав и инъекций.

TL;DR: утверждающие, что «скиллы, сгенерированные LLM, бесполезны», путают наличие знаний внутри модели и умение вытащить их на поверхность в нужный момент. Если встретите таких, покажите им скилл для генерирования скиллов, сгенерированный LLM'кой. В качестве аргумента вряд ли прокатит, зато реакция будет бесценной 🔥

#агенты
Please open Telegram to view this post
VIEW IN TELEGRAM
54👍2💯2
ipi-check.png
665.8 KB
🤩 ipi-check: теперь и аудитор скиллов

ipi-check получил важное обновление — фичу проверки безопасности скиллов:

• Автоматическое обнаружение каталогов на основе SKILL.md и сканирование их на предмет сбора учетных данных, удаленного выполнения кода, повышения привилегий, директив секретности и другого вредоносного поведения.

• Шаблоны обнаружения, специфичные для скиллов (IPI401–411) — для обфусцированного кода, злоупотребления динамическим контекстом, скрытых инструкций HTML и чрезмерных разрешений.

• LLM-based триажер и классификатор скиллов, ориентированный на обнаружение теневых функций (поведение, которое нельзя вывести из описания навыка).

Полный список фич можно посмотреть здесь.

🙌

#ИИ_безопасность #ИИ_инструменты
Please open Telegram to view this post
VIEW IN TELEGRAM
6👍1🔥1
Forwarded from OK ML
Взломать агента, не трогая его данные

Или защитить)

Снова про MCP и безопасность. В отличие от классической эксплуатации уязвимостей, side-channel атака не требует прямого доступа к данным. Даже если агент не раскрывает свои данные напрямую, он может непреднамеренно выдавать информацию через поведение:
🧙‍♀️ различное время выполнения tool calls;
🧙‍♀️ изменение размера ответов;
🧙‍♀️ вариации потребления ресурсов;
🧙‍♀️ характерные последовательности вызовов инструментов;
🧙‍♀️ особенности создания и завершения контекстов.

Такая информация может раскрывать внутреннее состояние агента.
Например:
🧙‍♂️ определить, использует ли агент конкретный инструмент;
🧙‍♂️ понять, обращался ли агент к внутренним корпоративным данным;
🧙‍♂️ выявить выполнение дорогостоящих операций;
🧙‍♂️ восстановить структуру агентного воркфлоу;
🧙‍♂️ обнаружить наличие скрытых инструкций или дополнительного контекста;
🧙‍♂️ подготовить более эффективную промпт-инъекцию.

Получается, что у злоумышленника появляется возможность постепенно профилировать поведение агентной системы 😎, не имея доступа к ее внутренним данным. Опасны и low-and-slow атаки, когда разведка ведется неделями небольшими порциями и не вызывает срабатывания классических сигнатурных средств защиты. 🐹Агент обычно отвечает за 200–300 мс. После серии специально подобранных запросов время ответа скачет до 2–3 секунд только при наличии доступа к определенному внутреннему инструменту. Даже без прямого доступа к данным атакующий получает бит информации о конфигурации системы. Повторяя эксперимент тысячи раз, можно постепенно восстановить внутреннюю архитектуру агента.

Здесь появляется интересная возможность для применения классического машинного обучения. Ура!
Для каждой MCP-сессии можно собирать признаки:
🐹 среднее и медианное время выполнения операций;
🐹 дисперсию задержек;
🐹 количество tool calls;
🐹 число уникальных инструментов;
🐹 размеры запросов и ответов;
🐹 частоту создания новых сессий;
🐹 JSON-RPC последовательности;
🐹 TLS fingerprint клиента;
🐹 потребление ресурсов на запрос.

После этого задача превращается в классическую задачу обнаружения аномалий, так как у нас нет размеченных атак, только норма:
🐹 One-Class SVM — построить картину нормального поведения
🐹 Local Outlier Factor — поискать локальную аномальность (когда несколько ролей у агентов)
🐹 HDBSCAN — можно нового клиента идентифицировать
🐹 LightGBM — лучше всего в прод, кмк. На подобных данных бустинг обычно уничтожает большинство других алгоритмов.
🐹🐹🐹 Да даже цепи Маркова!

Фактически получается поведенческий IDS для MCP-инфраструктуры (модель анализирует не содержимое запросов, а характеристики поведения клиента). Это уже классический UEBA — только теперь для агентных систем.

Все!
🎁
Please open Telegram to view this post
VIEW IN TELEGRAM
13💯2👍1🤣1
💻 Гайд по безопасной разработке на Go

Подготовил гайд для go-разработчиков с чек-листом и примерами, покрывающий оба OWASP Top 10 for Web Applications (2021+2025), плюс аспекты агентской разработки безопасных приложений на Go.

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

Буду невероятно рад фидбэку 🤓

#безопасность_кода #гайд
Please open Telegram to view this post
VIEW IN TELEGRAM
156🔥5👍2
🧩 Принципы и паттерны безопасной разработки: ISP

Часть 3.

А у нас на очереди, принцип разделения интерфейсов (Interface Segregation Principle, ISP — пожалуй, один из наиболее простых в SOLID), гласящий:

Клиенты не должны зависеть от интерфейсов, которые они не используют.


Проще говоря, лучше несколько узкоспециализированных интерфейсов, чем один «толстый», навязывающий потребителю кучу лишнего.

С точки зрения безопасности, ISP напрямую перекликается с принципом наименьших привилегий (Least Privilege). «Толстый» интерфейс — это расширенная поверхность атаки: клиент получает доступ к методам, которые ему для работы не нужны. Если один из таких методов оказывается привилегированной операцией, а её защита оказывается слабее ожидаемой, то любой потребитель интерфейса внезапно получает доступ к критичному функционалу.

💡Тривиальный пример:

interface IUserService {
User getProfile(Long id);
void updateProfile(User u);
void resetPassword(String email);
void deleteUser(Long id);
void assignRole(Long id, Role r);
List<User> exportAll();
}


Потребитель, которому нужно лишь отображать профиль, вынужден зависеть от deleteUser, assignRole и exportAll. Если защита реализована на уровне имплементации, а не интерфейса, то одна ошибка авторизации — и профильный компонент может удалять пользователей.

Что делать?

Нарушения ISP порождают целый ряд CWE, связанных с чрезмерно широким доступом:

CWE-749: Exposed Dangerous Method or Function
CWE-306: Missing Authentication for Critical Function
CWE-250: Execution with Unnecessary Privileges

В примере выше правильнее ввести два интерфейса, соответствующие уровням привилегий принятой в приложении модели доступа:

interface IUserProfile {
User getProfile(Long id);
void updateProfile(User u);
}

interface IUserAdmin {
void deleteUser(Long id);
void assignRole(Long id, Role r);
List<User> exportAll();
}


Компоненту, работающему с профилями, IUserAdmin будет попросту недоступен, даже при наличии бага в авторизации.

Разделение интерфейсов можно (и нужно) также проводить, и по границам доверия: один интерфейс не должен обслуживать функциональность по обе стороны от любой из границ, определенных моделью угроз.

В плане соблюдения ISP, среди мейнстримовых языков здесь выгодно выделяются два:

💻 Go — не запрещает «толстые» интерфейсы, но поощряет их дробление через удобство композиции и интерфейсы потребителей. Стандартную библиотеку этого языка вполне можно рассматривать, как эталон соблюдения ISP.

👣 Rust — та же композиционная история, но через трейты и необходимость соблюдения «orphan rule».

Забавно, что в этих языках есть и явный анти-паттерн, который не запрещен: пустой интерфейс (interface{} в Go / dyn Any в Rust). Это нарушение ISP: клиент зависит от всего и ни от чего одновременно. Они существуют для низкоуровневых нужд, и их использования стоит по-возможности избегать.

🐛 Жизненное

CVE-2023-22515 — Atlassian Confluence (Broken Access Control, CVSS 10.0).

Confluence использовал фреймворк XWork2 для маршрутизации HTTP-запросов. Через единый веб-интерфейс были доступны как пользовательские действия (просмотр/редактирование страниц), так и привилегированные операции первичной настройки (/setup/setupadministrator.action). В терминах ISP — один «толстый» интерфейс маршрутизации обслуживал и рядовых пользователей, и административный мастер установки.

Атакующий отправлял запрос, манипулирующий свойством bootstrapStatusProvider.applicationConfig.setupComplete через механизм привязки параметров XWork2, «сбрасывая» флаг завершённости установки. После этого endpoint создания администратора становился доступен без аутентификации — атакующий создавал собственный админский аккаунт и получал полный контроль.

Если бы интерфейс маршрутизации был сегрегирован (setup-эндпоинты физически изолированы от пользовательских, с отдельным middleware авторизации), манипуляция параметрами одного интерфейса не открыла бы доступ к другому.

В патче (разбор) эндпоинты, относящиеся к установочным действиям, блокируются после первичной установки, а маршрутизация разделена.

Часть 5.

TL;DR: «Толстый» интерфейс — расширенная поверхность атаки. Если клиент видит метод, то рано или поздно кто-то найдёт способ его вызвать. Стоит разделять интерфейсы, как по привилегиям, так и по границам доверия.

#безопасность_кода #гайд
Please open Telegram to view this post
VIEW IN TELEGRAM
4👍3
🙃 Эй, чем сегодня займемся, Брэйн?

Чёт стало скучно. Этот бесконечный цикл: обсудить и поставить задачу агенту → провести ревью → объяснить агенту, почему он на этот раз тупой → проверить фиксы → обновить спеки → прогнать на CI → повторить с новой задачей 🫠

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

#ИИ_инструменты
Please open Telegram to view this post
VIEW IN TELEGRAM
45👾3👍2
Forwarded from PAI (Andrey Y)
Про Docker sbx впервые на русском

Автор параноик. Искренне было боязно ставить агента на голую систему без изоляции. Крутил виртуалки, но блин, неудобно каждый раз стартовать полноценную VM под отдельный проект. Контейнеры отпали почти сразу, потому что не сохраняется состояние между запусками. А мудрить с внешним хранилищем сессий, ну, если есть желающие это сделать, го обсудим в комментариях:)

Агент, имеющий доступ к внешнему миру, будь то веб-серфинг или запуск консольных команд - это как русская рулетка с большим количеством пустых мест в барабане. Шанс отстрелить себе что-нибудь небольшой, но никогда не равен нулю. А есть еще атаки через промпт инъекции, тайпсквотиннг и цепочки поставок npm и pip, которые за прошедший год вертели вообще, кажется, все кто мог.

Отвечаю на вопрос «Как сделать так, чтобы ошметки не разлетелись дальше коробки?» в новой статье Полезайте в песочницу, мистер Claude: изолируем агента
👍3
Forwarded from OK ML
Сразу пять способов обойти PickleScan

Исследователи обнаружили сразу 5 уязвимостей, позволяющих создавать вредоносные pickle-файлы, которые успешно проходят проверку PickleScan как безопасные (тут по ссылке инструмент указан HF как официальный для скана pickle), а затем при десериализации выполняют произвольный код. Обычно мы про формат pickle 🥒 говорим скрипя зубами, а тут вообще его сканер попался! PickleScan используется при проверке моделей в ML-регистрах, CI/CD-пайплайнах и проектах, работающих с Python-моделями. Если он был единственным рубежом защиты, ранее проверенные модели стоит считать потенциально ненадежными и пересканировать.

Самая опасная — CVE-2026-56315 (CVSS 9.8). 🥒 Оказалось, что в блок-лист сканера не попали несколько модулей стандартной библиотеки Python, содержащих функции для запуска системных команд. Кроме того, найдены четыре независимых обхода через idlelib, torch.jit, numpy.f2py и profile (CVE-2025-71376, CVE-2025-71370, CVE-2025-71365, CVE-2025-71341).

Основная проблема в том, что PickleScan использует deny-list. Такой подход практически невозможно поддерживать в актуальном состоянии, так как достаточно пропустить одну новую функцию или нестандартный путь вызова, и 🍆 финита ля комедия - защита перестает работать.

По факту это далеко не первый раунд обходов PickleScan  — до этого уже были обходы от Sonatype (4 штуки, CVE-2025-1716/1889/1944/1945) и от JFrog (3 штуки, CVE-2025-10155/10156/10157), плюс отдельная история с CRC в ZIP-архивах.

🥒 Хороший пример того, почему в security критически важных инструментов allow-list значительно надежнее, чем бесконечное поддержание актуальности deny-list. Но даже allow-list для pickle — это полумера, тк сама механика __reduce__ слишком гибкая. 🤩 Поэтому в рекомендациях исследователей закономерно звучит совет переходить на safetensors/ONNX, где код просто негде исполнять (по ссылке в разделе best practices).
 
Все
🕺
Please open Telegram to view this post
VIEW IN TELEGRAM
5👍32💯1
Являются ли CVE'хами ложно-отрицательные срабатывания SAST?

Хочу немного дополнить пересланный выше 👆пост, и немного порассуждать вокруг вопроса, волновавшего, лично меня, с самого начала упомянутой истории с байпассами PickleScan.

Дело в том, что назначение CVE на каждый вид байпасса в SAST-инструменте — несправедливо и категорически неадекватно, как в рамках текущей экосистемы CVE, так и с позиции здравого смысла.

CVE (Common Vulnerabilities and Exposures) — это идентификатор для конкретной, известной уязвимости в программном продукте, которая существует в коде и может быть эксплуатирована.

False Negative (FN) в SAST — это отсутствие события, уязвимость, которую не удалось обнаружить. Заводить CVE на «отсутствие сигнала» — это все равно что заводить уголовное дело на сигнализацию в магазине, которая не сработала на конкретного воришку. База данных MITRE по их же политике предназначена для «воришек», а не ограничений функциональности средств анализа.

В общем виде задача детектирования уязвимости эквивалентна проблеме остановки → является неразрешимой задачей. И множество FN в ЛЮБОМ анализаторе бесконечно. Поэтому любой SAST-движок — это всегда эвристический компромисс между фолзами обоих родов, подробно рассказывал об этом ранее.

Если заводить CVE на каждый FN от анализатора, то мы столкнемся с абсурдом: каждая реальная уязвимость в мире потенциально будет иметь множество CVE: один на саму уязвимость (непосредственно в коде), а остальные — на все SAST-инструменты, которые ее не нашли. Это сделает базу CVE бесконечной и бесполезной, так как она захламится мета-проблемами.

Важный нюанс здесь: кто принимает решения на основе SAST?

Если инженер видит, что SAST ничего не нашел, и на этом основании утверждает, что код безопасен — это процессная ошибка самого разработчика или секчемпа.

SAST — это инструмент снижения рисков, а не гарантия безопасности (в отличие, скажем, от формальной верификации, или доказательного SAST, о котором фантазировал недавно). Ожидать от эвристического анализатора, так или иначе работающего на поиск признаков уязвимости, 100% покрытия — по меньшей мере наивно (по большей — просто тупо).

Искажение принимаемых решений по безопасности из-за FN — это проблема культуры DevSecOps и системы компенсирующих мер (ручной код-ревью, динамический анализ DAST, пентесты). Перекладывать эту ответственность на вендора SAST путем заведения CVE — это попытка решить внутреннюю организационную проблему техническим костылем, не более того.

TL;DR: если заводите CVE на ложно-отрицательное срабатывание в SAST-инструменте, будьте готовы к тому, что после исправления, ложно-положительных, требующих рутинного триажа с вашей же стороны, в нём станет на порядок-другой больше. Потому что этот компромисс именно так и работает.

А ещё лучше — поправьте свои процессы DevSecOps 🙂 Это прям реально нужно, раз FN от анализатора в них сейчас равноценен CVE.
Please open Telegram to view this post
VIEW IN TELEGRAM
6💯61😱1
Разработчики 🆚 ресерчеры

Уже много лет, как стало модно делить людей на «разработчиков» и «ресерчеров» (теперь ещё и на «экспертов», но сегодня не об этом). Должностные инструкции и оргструктура закрепляют это разграничение как данность, а в некоторых компаниях эти функции физически разнесены, не просто между должностями, но и между целыми направлениями. Однако же, если отвлечься от позиций в штатке, то на самом деле, это — два фундаментально различных режима мышления. Майндсета, способных и должных сосуществовать в голове одного инженера.

Различие между ними изучено достаточно хорошо. Ещё в 1991 году профессор Стэнфорда Джеймс Марч описал дилемму «exploration–exploitation» Exploration — это поиск нового, эксперимент, риск и открытие. Exploitation — исполнение, оптимизация, доведение до совершенства известного. И это, как мне кажется, прям идеально укладывается на реалии R&D.

• Исследовательский майндсет exploration в чистом виде: способность задавать вопросы без гарантии ответа, комфортно работать в условиях хаоса и неопределённости, видеть картину целиком и замечать неочевидные связи.

• Разработческий майндсет exploitation: умение декомпозировать сложную проблему на выполнимые шаги, доводить гипотезные PoC'и до релиза, принимать архитектурные компромиссы и добиваться воспроизводимого качества.

Есть удобная аналогия с правшами и левшами, и здесь она приходится, как нельзя кстати. Почти у каждого есть доминирующая рука, но в течение жизни мы всё же учимся использовать обе. С майндсетами та же история: у каждого есть склонность к одному из них, это нормально. Но почти всегда в фоне присутствует и второй. Распознать их не сложно.

Отличительные черты

• Исследовательский майндсет: толерантность к неопределённости, способность формулировать проверяемые гипотезы, понимать, чем они отличаются от фичей, и безжалостно их опровергать; навык быстрого входа в незнакомый домен, умение эффективно читать научную литературу и отделять сигнал от шума. Ключевой операционный скилл — мышление вне коробки: задавать вопросы, на которые ещё никто не пытался ответить, решать неразрешимые задачи, смотреть на систему снаружи, а не изнутри. Ключевой софт-скилл — безжалостность к опровержению. Исследователь должен быть готов к тому, что 9 из 10 не то, что гипотез — целых исследований, будут однажды прекращены или отправлены «под стол». Если у исследователя каждый результат его работы залетает в прод, это значит лишь то, что он ставит перед собой недостаточно амбициозные цели.

• Разработческий майндсет: системное мышление, умение смотреть на систему изнутри, с учетом всех причинно-следственных связей, допущений и tribal-knowledge; параноидальное внимание к edge-кейсам, дисциплина тестирования и документирования, навык оценки сроков и трудозатрат, способность принимать решения при неполноте данных и нести за них ответственность. Ключевой операционный скилл — декомпозиция задач, позволяющая получать понятные и прогнозируемые результаты в плане. Разработчик, ссылающийся на её отсутствие, сродни художнику, который жалуется, что ему дали чистый холст вместо «картинки по номерам». Ключевой софт-скилл — готовность к критике, как к способу стать лучше (ибо код-ревью и критикующие коллеги тут случаются чаще).

Как прокачивать

Исследовательский майндсет растёт через чтение и реферирование научных статей вне зоны комфорта (это несложно), участие в исследовательских хакатонах без ожидания немедленного практического результата, документирования гипотез и экспериментов с целью выявления в них причинно-следственных связей. Хорошее упражнение: взять технологию и задать цепочку из десяти «почему?», добираясь до фундаментальных ограничений. Ещё одно (практикуемое автором много лет): прочитав абстракты очередной научной статьи, отложить её в сторону и пофантазировать на тему «как бы я решил эту проблему, если бы умел?». И возвращаться к чтению статьи только после формирования в голове понятного тезисного плана решения поставленной в ней проблемы.

Разработческий майндсет формируется через участие в опенсорс-проектах с жёстким код-ревью, привычку доводить пет-проекты до состояния «может использоваться кем-то ещё», регулярное решение алгоритмических задач с ограничением по времени (да-да, олимпиады, Codeforces и LeetCode). Главное упражнение: взять чужой исследовательский прототип и превратить его в готовую к проду систему — с полной реализацией всех фичей, обозреваемостью, тестами, обработкой ошибок и документацией.

Ни один майндсет не правильнее и не ценнее другого. Исследователь без разработчика производит красивые, но бесполезные артефакты; разработчик без исследователя эффективно строит не то, что нужно бизнесу и пользователям. Подлинный инженер живёт в постоянном конфликте между exploration и exploitation и использует его как источник энергии, а не выбирает одну сторону и окапывается в ней. Инженер R&D — не должность, не диплом и даже не состояние души.

Это человек, в мышлении которого неразрывно сплавлены, как вопрошающая любознательность исследователя, так и конструктивная, доводящая до финального результата, воля разработчика.

#мысли_вслух
Please open Telegram to view this post
VIEW IN TELEGRAM
69👍6💯3
🖥 Скилл `code-review`

Казалось бы, зачем ещё один скилл для ревью изменений в коде? Но вот нет, существующие — то не покрывают логические ошибки, то полностью забивают на безопасность, то не дают рекомендаций по исправлению, и т.п.

В конце-концов, кто я такой, чтобы не следовать принципу NIH (Not Invented Here)? 🤓

Если серьёзно, то сделал его для встраивания в c0wrk, но скилл получился достаточно сбалансированным, во-первых, и с нормальным покрытием вопросов безопасности, во-вторых. Поэтому решил выделить его и в свою коллекцию, вдруг кому-то окажется полезен и с другими агентами.

Лежит здесь, агностичен относительно конкретных агентов и экосистем, предназначен для полноценного ревью изменений (локальных, в конкретных коммитах, ветках или PR/MR), помимо обычных проверок, покрывает также весь OWASP для веб и агентских приложений.

Пример реального отчета скину в комменты.

#ИИ_инструменты
Please open Telegram to view this post
VIEW IN TELEGRAM
10102👍2🔥1😱1
😁7🤔1🐳1💯1
Крайне рекомендую к просмотру 🙂
Please open Telegram to view this post
VIEW IN TELEGRAM
Forwarded from Библиотека программиста
🎬 Как ИИ ускоряет разработку и где ломаются архитектуры

Мы провели открытый вебинар, где разобрали реальные боли проектирования автономных систем. Ольга Лукьянова на практическом кейсе показала, как использовать ИИ-ассистентов для реальных задач. Вы просили запись встречи — она уже в открытом доступе!

Что внутри:

— Как с помощью ИИ быстрее разбираться в незнакомом коде и готовить пулл-реквесты;
— Критерии выбора между одним агентом и мультиагентной системой;
— Разбор популярных архитектурных ошибок и ограничений современных ИИ;
— Практические рекомендации по проектированию и внедрению облачных агентов.

👉 Посмотреть полную запись можно тут:
VK
YouTube

🚀 Хотите пойти дальше открытого вебинара? Если вы готовы перейти от простых промптов к проектированию надежных, отказоустойчивых ИИ-систем, которые не сливают бюджет компании на API, приходите на курс AgentOps. Поток уже стартовал, но двери еще приоткрыты!

👉 Успеть на курс AgentOps
53👍3
🖼 Изображения с текстом ради экономии токенов: не всё так просто

На прошлой неделе буквально в каждом релевантном паблике проскочил проект pxpipe — тула, позволяющая экономить расход токенов за счет преобразования контекстного текста в изображения, при работе с VLM. Ещё дальше зашел Can Bölük (боюсь пытаться написать это по-русски) — автор кодинг-агента oh-my-pi. Это вообще мой кумир, кроме шуток и без сарказма. Подписки на обновы в его проекте в принципе достаточно, чтобы быть в курсе вообще всех инноваций, которым можно найти хоть какое-то применение в кодинг-агентах. Так вот он, примерно в одно время с автором pxpipe, вообще сделал этот подход одной из стратегий сжатия контекста (SnapCompact) в своём агенте.

Идея превращать текст в изображения перед отправкой в VLM звучит безусловно прикольно. Механика проста: текстовый токен — дискретная единица из словаря ~50K–200K, один токен в среднем кодирует ~2.5-3 символа для плотного контента (код, JSON). Визуальный токен — патч, скажем, в 28×28 пикселей в непрерывном пространстве эмбеддингов, и может принимать любое значение. Плотность — на порядок выше. По формуле Anthropic, изображение 1568×728 стоит ~1522 токена и вмещает ~28 000 символов — сжатие ~4.6× по входным токенам.

Ну, зашибись же? Вот... не совсем.

Коэффициент экономии 10× по входным токенам — действительно имеет место, но он относится к специализированной модели DeepSeek-OCR с кастомным энкодером, обученным именно на оптическое сжатие. Для VLM общего назначения (Claude, GPT) реальный выигрыш скромнее — 2–3×. pxpipe на реальном трафике Claude Code показал −68% входных токенов, а академическое исследование зафиксировало лишь ~2× без потери качества. SWE-bench Lite: 10/10 задач решены на обоих arms, стоимость $27 vs $53 (−49%) — но это лишь 10 задач, как-то маловато для статистической значимости.

О чём ещё постоянно забывают упомянуть хайп-посты на эту тему — это «налог» на декодирование. Чтение плотного изображения является вычислительно тяжёлой задачей: модель тратит лишние thinking-токены на распознавание. Для SnapCompact его автор провел тщательные замеры: output-токены +333%, thinking-токены +561%. При ценах Anthropic на Sonnet ($3/$15) один проход оказался на 28% дороже текста. Независимый эксперимент PageWatch подтвердил картину: GPT-5 экономит −40% prompt-токенов, но completion-токены выросли у всех моделей, съедая всю экономию. Выгода появляется только в очень длинных сессиях с переиспользованием KV-кэша.

Другой проблемой являются конфабуляции (эх, прочитал бы это старина Зигмунд): при ошибках чтения модель не признаётся в неуверенности, и выдаёт правдоподобные, но неверные значения. Аудит pxpipe: точное воспроизведение hex-строк — лишь 38%, с систематической путаницей глифов (0⇆O, 6⇆8, 5⇆S, camelCase→lowercase). Opus 4.8 набрал 0/15 на hex-recall и поэтому отключён в pxpipe по умолчанию. Из реальных примеров: модель «вспомнила» имя человека из истории чата — уверенно, но неверно. Fable 5 читает рендеры почти идеально: 100/100 на novel arithmetic, 98/98 на gist recall. GPT-5.6 тоже силён. При этом Opus 4.8 ошибается в ~7% случаев, а вот GPT-5.5 деградирует примерно вхлам на контексте в изображениях. Универсального решения нет — метод не модель-агностический.

Попутно выяснилось, что помимо дискриминации китайцев, Anthropic ещё и молча уменьшает изображения больше ~1.15 MP (downscale ~0.555×), но выставляет счёт за полные пиксели ↗️ Без коррекции геометрии (≤1568×728) экономия размывается, а ёмкость страницы падает с ~92 000 до ~28 000 символов — нужно в 3.3× больше изображений.

Отдельной болью является выбор подходящего шрифта для рендера текста в изображение. Ниже 35–40 px² на символ наступает обрыв: транскрипция падает с 0.79 до 0.02. Мельче — уже не дешевле, с учетом стоимости ошибок. Шрифт 4×6 даёт 102K символов на страницу, но модель читает лишь 2% — экономия токенов тут оборачивается полной потерей смысла (здравого, по крайней мере).

TL;DR: так что метод прикольный, идея заслуживает внимания, но... относиться к этому стоит, скорее, как ко временному багу тарификации, не более того.

В c0wrk, пожалуй, я это тянуть не буду 🙂

#ИИ_инструменты
Please open Telegram to view this post
VIEW IN TELEGRAM
54👍3💔1
🧩 Принципы и паттерны безопасной разработки: DIP

Часть 4.

Принцип инверсии зависимостей (Dependency Inversion Principle, DIP) утверждает: модули верхнего уровня не должны зависеть от модулей нижнего уровня, оба должны зависеть от абстракций. При этом не абстракции должны зависеть от деталей, а детали — от абстракций.

С точки зрения безопасности, нарушение DIP означает, что высокоуровневая логика (принятие решений, обработка входных данных) жёстко привязана к конкретной низкоуровневой реализации. Когда эта реализация меняется или расширяет поверхность атаки — высокоуровневый модуль наследует проблему автоматически, без какого-либо контроля на своей стороне.

💡 Пример

// С нарушением DIP
class DataBinder {
void bind(Object target, Map<String,String> params) {
for (PropertyDescriptor pd :
Introspector.getBeanInfo(target.getClass())
.getPropertyDescriptors()) {
if (params.containsKey(pd.getName()))
pd.getWriteMethod().invoke(target, params.get(pd.getName()));
}
}
}

// С соблюдением DIP
interface BindablePropertyResolver {
List<BindableProperty> resolve(Class<?> type);
}

class DataBinder {
private final BindablePropertyResolver resolver;

void bind(Object target, Map<String,String> params) {
for (BindableProperty bp : resolver.resolve(target.getClass())) {
if (params.containsKey(bp.name()) && bp.isSafe())
bp.set(target, params.get(bp.name()));
}
}
}


Абстракция BindablePropertyResolver контролируется высокоуровневым модулем и определяет контракт: что можно связывать, а что — нет. Даже если интроспекция обнаружит новые свойства, они не станут доступны без явного разрешения.

Помимо архитектурного разделения, главным правилом остается биндинг входных данных строго к выделенным DTO (Data Transfer Objects), а не к доменным сущностям или объектам фреймворка. DTO содержит только явно разрешенные поля, что исключает динамический биндинг опасных свойств.

Нарушения DIP провоцируют:

• CWE-913: Improper Control of Dynamically-Managed Code Resources
• CWE-470: Use of Externally-Controlled Input to Select Classes or Code
• CWE-915: Improperly Controlled Modification of Dynamically-Determined Object Attributes

🐛 Жизненное

CVE-2022-22965 — Spring Framework RCE, она же Spring4Shell (CVSS 9.8).

Механизм привязки параметров (data binding) в Spring MVC — высокоуровневый модуль, отвечающий за маппинг HTTP-параметров в свойства Java-объектов. Внутри он напрямую зависит от низкоуровневого Java Beans Introspection API (CachedIntrospectionResults → java.beans.Introspector), рекурсивно обходящего цепочки геттеров/сеттеров.

На JDK 8 существовал чёрный список: Spring блокировал доступ к class.classLoader. Но в JDK 9 у Class появился новый геттер — getModule(). Через него открылся обходной путь class.module.classLoader, не попавший в чёрный список. Цепочка:

class.module.classLoader.resources.context.parent.pipeline.first.*

позволяла модифицировать конфигурацию Tomcat AccessLogValve — атакующий менял путь, паттерн и суффикс лога, записывая на диск JSP-файл (web shell).

Нарушение DIP здесь в том, что data binding напрямую зависел от конкретного механизма интроспекции (низкоуровневая деталь), без абстракции, определяющей контракт: какие свойства разрешено связывать. Когда деталь (набор доступных PropertyDescriptor-ов) изменилась из-за развития JDK — поверхность атаки расширилась без единого изменения в коде самого Spring.

🔧 Как пофиксили

Spring не стал внедрять глобальный белый список (чтобы не сломать обратную совместимость), и добавил чёрный, на уровне интроспекции. Доступ к свойствам Class, classLoader и protectionDomain был полностью заблокирован, что разорвало опасную цепочку... до следующего витка развития JDK, видимо 😬

💻 Как насчет композиционных языков?

Оставим это на правах домашнего задания: подумать, как Rust поощряет DIP через трейты, а Go — делая упор на простоту, снижение шаблонного кода и неявные интерфейсы.

TL;DR: Если модуль верхнего уровня напрямую зависит от деталей реализации нижнего — любое изменение внизу может молча расширить поверхность атаки наверху. Инвертируйте зависимость: пусть высокоуровневый модуль определяет контракт допустимых данных, а низкоуровневый — реализует его. А на входе всегда используйте DTO.

#безопасность_кода #гайд
Please open Telegram to view this post
VIEW IN TELEGRAM
62👍1💯1
sp4rk: SDK для разработки ИИ-агентов на Go

Выделил из c0wrk в отдельный проект sp4rk SDK, на котором он основан. Умеет практически* всё, что нужно для построения мультиагентных систем на Go, и предоставляет два API (можно смешивать):

• классический — для полного контроля над всеми компонентами и их конфигурацией;
• «текучий» (fluent) — для быстрого построения агентов из заготовленных блоков.

Например, игрушечный триажер тикетов для Github-репозитория, с MCP, сессионной памятью, DAG-планированием и рефлексией в случае проблем, во fluent-варианте выглядит так:

system := "You are a triage agent. Use the github tools, verify each result, then call finish with a short report."

task := "Find the 5 most recent open issues in v0lka/sp4rk with the `error-handling` label, summarize each in one line, and save the digest as a fact for the next step."

github := mcp.ServerEntry{
Transport: "stdio",
Command: "npx",
Args: []string{"-y", "@modelcontextprotocol/server-github"},
Env: map[string]string{"GITHUB_PERSONAL_ACCESS_TOKEN": "${…}"},
}

result, err := sp4rk.NewF().
Anthropic(os.Getenv("ANTHROPIC_API_KEY"), "claude-sonnet-5").
MCPServer("github", github).
MemoryTools().
AutoApprove().
MaxSteps(25).
System(system).
Task(context.Background(), task).
Plan().
Reflect().
MaxRetries(2).
Execute()


Больше примеров — есть в /examples и документации.

Ещё даже не бета (выйдет вместе с бетой c0wrk), но уже достаточно стабильный, чтобы пробовать.

* — практически, потому что пока не реализованы потоковые ответы LLM, и сейчас поддерживаются только синхронные. Это есть в планах, до релиза v1.

#ИИ_инструменты
Please open Telegram to view this post
VIEW IN TELEGRAM
13👏6🔥21
😸 Как улучшить работу агента с codebase-memory-mcp?

MCP codebase-memory-mcp — добротный инструментарий, позволяющий экономить тонны токенов на исследования кодовой базы и получать парой вызовов своих инструментов то, на что у агента ушли бы десятки [rip]grep, glob, read_file, etc.

Однако, в силу используемых в нём описаний инструментов, и способа интеграции с агентами, некоторым из них оказывается неочевиден воркфлоу работы с этим MCP, что приводит к ошибкам (чаще всего, связанным с идентификаторами проектов) и невозможности использовать любой из его инструментов.

Ситуацию можно исправить, если добавить в AGENTS.md проекта или агента (или в правила агента, или во что угодно, что гарантировано попадет в контекстное окно любой сессии) следующую подсказку:

## Codebase navigation via `codebase-memory-mcp` (if available)

If the `codebase-memory-mcp` MCP server is connected (e.g. its tools appear with an `[MCP]` prefix), prefer it for code discovery, call-graph tracing, and architecture questions instead of broad manual `grep`/`glob` sweeps. **Every project-scoped tool requires a project identifier.** Calling such a tool without the correct identifier returns an error of the form `project not found or not indexed` (with a hint listing the available projects).

### Project identifier

The identifier is derived from the repository's **absolute path**: replace every path separator (`/`) with `-` and drop the leading slash.

| Repository path | Project identifier |
| ----------------------------------- | ---------------------------------------- |
| `/path/to/repo` | `path-to-repo` |

`index_repository` accepts an optional `name` argument that overrides this derived identifier. **Do not set it** — it creates a separate project entry alongside the path-derived one and breaks the predictable identifier rule. Always let the identifier be derived from the path.

### Required workflow

1. **Verify the project is indexed** — call `list_projects` first (it takes no arguments). Compute the expected identifier from the repo path (rule above) and check it against the returned `projects[].name` list (or match by `root_path`).
2. **Index if absent** — if the project is missing, call `index_repository(repo_path=<absolute path>)` (omit `name`). Read the returned `project` field to confirm the actual identifier; it equals the path-derived form. Use `mode="fast"` for a quick pass, `"full"` when you need similarity/semantic edges.
3. **Pass the identifier to the tools** — supply it as the `project` argument to every project-scoped tool. Without it, the tool errors out and will not query the graph.

### Tools by purpose

- **Discover** — `search_graph` (BM25 + semantic + regex over functions/classes/routes), `search_code` (grep augmented by the call graph), `get_architecture` (packages, clusters, layers, hotspots).
- **Read code** — `get_code_snippet` (read a function/class by `qualified_name`; resolve it first via `search_graph`).
- **Trace relationships** — `trace_path` (callers/callees, data flow, cross-service hops), `query_graph` (raw Cypher for multi-hop/aggregate queries).
- **Change & impact** — `detect_changes` (diff vs a git ref + blast radius), `get_graph_schema` (node labels / edge types).
- **Index management** — `index_repository`, `index_status`, `list_projects`, `delete_project`, `ingest_traces` (runtime traces), `manage_adr` (Architecture Decision Records).


🙌

#ИИ_инструменты
Please open Telegram to view this post
VIEW IN TELEGRAM
12🔥2💯1