Сведения о безопасности
Чему вы научитесь
- Как плагин защищает вашу систему от угроз безопасности
- Какие правила безопасности должны соблюдать файлы навыков
- Лучшие практики безопасности при использовании плагина
Основная концепция
Плагин OpenCode Agent Skills работает в вашей локальной среде, выполняя скрипты, читая файлы и разбирая конфигурации. Несмотря на его мощь, если файлы навыков поступают из ненадёжных источников, это может создать риски безопасности.
При проектировании плагина встроены многоуровневые механизмы безопасности, словно несколько защитных ворот: от доступа к путям и разбора файлов до выполнения скриптов — каждый слой строго контролируется. Понимание этих механизмов поможет вам использовать плагин безопаснее.
Подробное описание механизмов безопасности
1. Проверка безопасности путей: предотвращение выхода за пределы каталога
Проблема: Если файл навыков содержит злонамеренный путь (например, ../../etc/passwd), это может позволить доступ к чувствительным системным файлам.
Защитные меры:
Плагин использует функцию isPathSafe() (строки 130-133 в src/utils.ts), чтобы гарантировать, что все обращения к файлам ограничены каталогом навыка:
export function isPathSafe(basePath: string, requestedPath: string): boolean {
const resolved = path.resolve(basePath, requestedPath);
return resolved.startsWith(basePath + path.sep) || resolved === basePath;
}Как это работает:
- Запрошенный путь преобразуется в абсолютный
- Проверяется, начинается ли преобразованный путь с каталога навыка
- Если путь пытается выйти за пределы каталога навыка (содержит
..), доступ отклоняется
Практические примеры:
Когда инструмент read_skill_file читает файл (строки 101-103 в src/tools.ts), он сначала вызывает isPathSafe:
// Security: ensure path doesn't escape skill directory
if (!isPathSafe(skill.path, args.filename)) {
return `Invalid path: cannot access files outside skill directory.`;
}Это означает:
- ✅
docs/guide.md→ Разрешено (внутри каталога навыка) - ❌
../../../etc/passwd→ Отклонено (попытка доступа к системному файлу) - ❌
/etc/passwd→ Отклонено (абсолютный путь)
Почему это важно
Атаки выхода за пределы каталога (path traversal) — распространённая уязвимость веб-приложений. Даже если плагин работает локально, ненадёжные навыки могут попытаться получить доступ к вашим SSH-ключам, конфигурациям проектов и другим чувствительным файлам.
2. Безопасный парсинг YAML: предотвращение выполнения кода
Проблема: YAML поддерживает пользовательские теги и сложные объекты. Злонамеренный YAML может выполнить код через теги (например, !!js/function).
Защитные меры:
Плагин использует функцию parseYamlFrontmatter() (строки 41-49 в src/utils.ts), применяя строгую стратегию парсинга YAML:
export function parseYamlFrontmatter(text: string): Record<string, unknown> {
try {
const result = YAML.parse(text, {
// Use core schema which only supports basic JSON-compatible types
// This prevents custom tags that could execute code
schema: "core",
// Limit recursion depth to prevent DoS attacks
maxAliasCount: 100,
});
return typeof result === "object" && result !== null
? (result as Record<string, unknown>)
: {};
} catch {
return {};
}
}Ключевые параметры безопасности:
| Параметр | Назначение |
|---|---|
schema: "core" | Поддерживает только базовые JSON-типы (строки, числа, логические значения, массивы, объекты), отключает пользовательские теги |
maxAliasCount: 100 | Ограничивает глубину рекурсии алиасов YAML для предотвращения DoS-атак |
Практические примеры:
# Злонамеренный пример YAML (будет отклонён схемой core)
---
!!js/function >
function () { return "malicious code" }
---
# Правильный безопасный формат
---
name: my-skill
description: A safe skill description
---Если парсинг YAML не удаётся, плагин молча игнорирует навык и продолжает обнаруживать другие навыки (строки 142-145 в src/skills.ts):
let frontmatterObj: unknown;
try {
frontmatterObj = parseYamlFrontmatter(frontmatterText);
} catch {
return null; // Ошибка парсинга, пропуск этого навыка
}3. Валидация ввода: строгая проверка Zod Schema
Проблема: Поля frontmatter навыка могут не соответствовать спецификации, что приведёт к аномальному поведению плагина.
Защитные меры:
Плагин использует Zod Schema (строки 105-114 в src/skills.ts) для строгой валидации frontmatter:
const SkillFrontmatterSchema = z.object({
name: z.string()
.regex(/^[\p{Ll}\p{N}-]+$/u, { message: "Name must be lowercase alphanumeric with hyphens" })
.min(1, { message: "Name cannot be empty" }),
description: z.string()
.min(1, { message: "Description cannot be empty" }),
license: z.string().optional(),
"allowed-tools": z.array(z.string()).optional(),
metadata: z.record(z.string(), z.string()).optional()
});Правила валидации:
| Поле | Правило | Отклоняемые примеры |
|---|---|---|
name | Строчные буквы, цифры, дефисы, не может быть пустым | MySkill (заглавные), my skill (пробел) |
description | Не может быть пустым | "" (пустая строка) |
license | Необязательная строка | - |
allowed-tools | Необязательный массив строк | [123] (не строки) |
metadata | Необязательный объект key-value (значения — строки) | {key: 123} (значение не строка) |
Практические примеры:
# ❌ Ошибка: name содержит заглавные буквы
---
name: GitHelper
description: Git operations helper
---
# ✅ Правильно: соответствует спецификации
---
name: git-helper
description: Git operations helper
---Если валидация не проходит, плагин пропускает навык (строки 147-152 в src/skills.ts):
let frontmatter: SkillFrontmatter;
try {
frontmatter = SkillFrontmatterSchema.parse(frontmatterObj);
} catch (error) {
return null; // Ошибка валидации, пропуск этого навыка
}4. Безопасность выполнения скриптов: выполняются только исполняемые файлы
Проблема: Если плагин выполняет произвольные файлы (например, файлы конфигурации, документацию), это может привести к неожиданным последствиям.
Защитные меры:
При обнаружении скриптов (строки 59-99 в src/skills.ts) плагин собирает только файлы с правами на выполнение:
async function findScripts(skillPath: string, maxDepth: number = 10): Promise<Script[]> {
const scripts: Script[] = [];
const skipDirs = new Set(['node_modules', '__pycache__', '.git', '.venv', 'venv', '.tox', '.nox']);
// ... логика рекурсивного обхода ...
if (stats.isFile()) {
// Ключевой момент: только файлы с битом исполнения
if (stats.mode & 0o111) {
scripts.push({
relativePath: newRelPath,
absolutePath: fullPath
});
}
}
// ...
}Характеристики безопасности:
| Механизм проверки | Назначение |
|---|---|
Проверка бита исполнения (stats.mode & 0o111) | Выполняются только файлы, явно помеченные пользователем как исполняемые, предотвращая случайное выполнение документации или конфигураций |
Пропуск скрытых каталогов (entry.name.startsWith('.')) | Не сканируются скрытые каталоги типа .git, .vscode, чтобы избежать сканирования слишком большого количества файлов |
Пропуск каталогов зависимостей (skipDirs.has(entry.name)) | Пропускаются node_modules, __pycache__ и т.д., чтобы избежать сканирования сторонних зависимостей |
Ограничение глубины рекурсии (maxDepth: 10) | Глубина рекурсии ограничена 10 уровнями, предотвращая проблемы с производительностью из-за глубоких каталогов в злонамеренных навыках |
Практические примеры:
В каталоге навыка:
my-skill/
├── SKILL.md
├── deploy.sh # ✓ Исполняемый (распознаётся как скрипт)
├── build.sh # ✓ Исполняемый (распознаётся как скрипт)
├── README.md # ✗ Неисполняемый (не распознаётся как скрипт)
├── config.json # ✗ Неисполняемый (не распознаётся как скрипт)
└── node_modules/ # ✗ Пропускается (каталог зависимостей)
└── ... # ✗ ПропускаетсяЕсли вызвать run_skill_script("my-skill", "README.md"), то из-за отсутствия прав на выполнение у README.md файл не будет распознан как скрипт (строка 86 в src/skills.ts), и функция вернёт ошибку "not found" (строки 165-177 в src/tools.ts).
Лучшие практики безопасности
1. Получайте навыки из надёжных источников
- ✓ Используйте официальные репозитории навыков или доверенных разработчиков
- ✓ Проверяйте количество GitHub Star и активность контрибьюторов навыка
- ✗ Не скачивайте и не запускайте навыки из неизвестных источников
2. Рецензируйте содержимое навыков
Перед загрузкой нового навыка быстро просмотрите SKILL.md и файлы скриптов:
# Посмотреть описание и метаданные навыка
cat .opencode/skills/skill-name/SKILL.md
# Проверить содержимое скриптов
cat .opencode/skills/skill-name/scripts/*.shОбратите особое внимание на:
- Доступны ли скрипты к чувствительным системным путям (
/etc,~/.ssh) - Устанавливают ли скрипты внешние зависимости
- Модифицируют ли скрипты системную конфигурацию
3. Правильно устанавливайте права на скрипты
Добавляйте права на выполнение только для тех файлов, которые явно должны выполняться:
# Правильно: добавить права на выполнение для скрипта
chmod +x .opencode/skills/my-skill/tools/deploy.sh
# Правильно: документация остаётся с правами по умолчанию (неисполняемая)
# README.md, config.json и т.д. не требуют выполнения4. Скрывайте чувствительные файлы
В каталоге навыка не должно быть чувствительной информации:
- ✗ Файлы
.env(API-ключи) - ✗ Файлы
.pem(закрытые ключи) - ✗
credentials.json(учётные данные) - ✓ Используйте переменные окружения или внешние конфигурации для управления чувствительными данными
5. Навыки уровня проекта перекрывают навыки уровня пользователя
Приоритет обнаружения навыков (строки 241-246 в src/skills.ts):
.opencode/skills/(уровень проекта).claude/skills/(уровень проекта, Claude)~/.config/opencode/skills/(уровень пользователя)~/.claude/skills/(уровень пользователя, Claude)~/.claude/plugins/cache/(кэш плагинов)~/.claude/plugins/marketplaces/(маркетплейс плагинов)
Лучшие практики:
- Специфичные для проекта навыки помещайте в
.opencode/skills/— они автоматически перекроют одноимённые навыки уровня пользователя - Общие навыки помещайте в
~/.config/opencode/skills/— будут доступны во всех проектах - Не рекомендуется глобально устанавливать навыки из ненадёжных источников
Итог урока
Плагин OpenCode Agent Skills имеет встроенную многоуровневую защиту:
| Механизм безопасности | Защищаемая цель | Расположение в коде |
|---|---|---|
| Проверка безопасности путей | Предотвращает выход за пределы каталога, ограничивает область доступа к файлам | utils.ts:130-133 |
| Безопасный парсинг YAML | Предотвращает выполнение кода в злонамеренном YAML | utils.ts:41-49 |
| Валидация Zod Schema | Гарантирует соответствие frontmatter навыка спецификации | skills.ts:105-114 |
| Проверка исполняемости скриптов | Выполняются только файлы, явно помеченные пользователем как исполняемые | skills.ts:86 |
| Логика пропуска каталогов | Избегает сканирования скрытых каталогов и каталогов зависимостей | skills.ts:61, 70 |
Помните: безопасность — это общая ответственность. Плагин предоставляет механизмы защиты, но окончательное решение за вами — используйте только навыки из надёжных источников и выработайте привычку рецензировать код.
Предварительный обзор следующего урока
На следующем уроке мы изучим Лучшие практики разработки навыков.
Вы узнаете:
- Правила именования и советы по составлению описаний
- Организацию каталогов и использование скриптов
- Лучшие практики для Frontmatter
- Как избежать распространённых ошибок
Приложение: Справочник исходного кода
Нажмите, чтобы раскрыть расположение исходного кода
Обновлено: 2026-01-24
| Механизм безопасности | Путь к файлу | Номера строк |
|---|---|---|
| Проверка безопасности путей | src/utils.ts | 130-133 |
| Безопасный парсинг YAML | src/utils.ts | 41-56 |
| Валидация Zod Schema | src/skills.ts | 105-114 |
| Проверка исполняемости скриптов | src/skills.ts | 86 |
| Логика пропуска каталогов | src/skills.ts | 61, 70 |
| Безопасность путей в инструментах | src/tools.ts | 101-103 |
Ключевые функции:
isPathSafe(basePath, requestedPath)— проверяет безопасность пути, предотвращая выход за пределы каталогаparseYamlFrontmatter(text)— безопасно разбирает YAML, используя core schema и ограничение рекурсииSkillFrontmatterSchema— Zod schema, валидирующая поля frontmatter навыкаfindScripts(skillPath, maxDepth)— рекурсивно находит исполняемые скрипты, пропуская скрытые и зависимые каталоги
Ключевые константы:
maxAliasCount: 100— максимальное количество алиасов при парсинге YAML для предотвращения DoS-атакmaxDepth: 10— максимальная глубина рекурсии при обнаружении скриптов0o111— маска бита исполнения (проверка, является ли файл исполняемым)