GitHub Agent Plugins 1.0 설치 전 권한 점검: 저장소 지침 확인하기
GitHub Agent Plugins 1.0 설치 전 권한 점검은 plugin.json의 이름과 버전을 확인하는 작업으로 끝나지 않는다. 2026년 8월 12일 공개된 이 형식은 Agent Skills와 MCP 서버를 휴대 가능한 구성요소로 묶으며, 조건에 따라 스크립트·로컬 프로세스·원격 연결과 클라이언트 전용 hook까지 동작 범위에 들어온다. 하지만 1.0의 루트 manifest에는 이 동작을 한 번에 보여주는 권한 선언 필드가 없다.
이 글은 2026년 8월 14일 공식 사양과 GitHub·VS Code 문서, 공식 예제 저장소를 대조한 결과를 바탕으로 한다. Linux 7.0.0-1009-aws x86_64와 jq 1.7에서 ../bin/audit와 ./bin/audit의 패키지 경로 조건만 정적으로 비교했으며, VS Code·Copilot CLI·Copilot app에 실제 플러그인을 설치하거나 활성화하지 않았다. 조직 정책과 sandbox 동작도 재현하지 않았다. 목표는 설치 성공을 약속하는 것이 아니라 승인 전에 무엇을 열어 보고, 어느 조건에서 보류할지를 정하는 데 있다.
20초 핵심 요약
- 무엇: 플러그인 패키지, 저장소 지침, MCP·hook, 조직 정책을 네 층으로 나눠 검사한다.
- 왜: manifest가 유효해도 스크립트 실행, 외부 연결, 저장소 지침 합성으로 예상보다 넓은 동작이 가능하다.
- 어떻게: 출처와 revision을 고정하고 전체 tree를 읽은 뒤, 실행 경계와 effective policy를 대조해 제한된 저장소에서만 시험한다.
승인 대상은 manifest가 아니라 네 개의 권한 층이다
Agent Plugins 1.0의 휴대 가능한 core는 루트 plugin.json, skills/<name>/SKILL.md, 선택 사항인 루트 mcp.json이다. plugin.json의 허용 필드는 스키마, 이름, 버전, 설명, 저자, 홈페이지, 저장소, 라이선스, 키워드, extensions다. 휴대 가능한 권한 목록은 여기에 없다. schema validation 통과는 패키지 형식이 맞다는 뜻이지 최소 권한이나 안전성을 증명하지 않는다. 이 구분은 Agent Plugins 1.0 사양의 manifest와 component 정의에 근거한다.
설치 여부를 판단할 때는 다음 네 층을 나눠서 본다.
| 층 | 확인 대상 | 놓쳤을 때 생기는 오판 |
|---|---|---|
| 패키지 형식 | plugin.json, skills/, mcp.json, package root 안의 경로 |
schema 통과를 전체 안전성으로 오해한다 |
| 지침 입력 | SKILL.md, references, scripts, 대상 저장소의 AGENTS.md와 Copilot instructions |
실제 요청에 합쳐지는 행동 조건을 빠뜨린다 |
| 실행 경계 | stdio command, 원격 MCP URL, hooks, ${PLUGIN_DATA} |
로컬 실행·외부 전송·지속 상태를 문서 기능으로만 본다 |
| 조직·클라이언트 정책 | marketplace, MCP allow/deny, bypass 금지, sandbox, team override | 선언된 정책과 실제 사용자에게 적용되는 정책을 혼동한다 |

패키지 경로 포함 규칙과 runtime sandbox도 구분해야 한다. 사양은 플러그인 파일 경로가 plugin root 밖으로 벗어나면 거부하도록 요구하지만, 이 규칙은 subprocess가 실행된 뒤 접근할 파일이나 네트워크를 제한하지 않는다. path 검사와 실행 권한 검사는 서로 다른 승인 항목이다. stdio와 원격 MCP, package-visible env·headers의 처리까지 포함한 근거는 Agent Plugins 1.0 사양 §4.1·§7.2.1·§9에서 확인할 수 있다.
source를 고정한 뒤 저장소 전체 tree를 연다
판단의 출발점은 marketplace 화면이 아니라 검토할 정확한 source다. marketplace 이름, publisher, source repository, plugin path, version 또는 commit ref를 기록한다. 갱신 가능한 branch만 가리키거나 publisher와 repository의 관계를 설명할 수 없다면 검토 대상을 고정할 수 없으므로 설치를 보류한다. private repository 기반 플러그인은 실제 사용자에게 그 source를 읽을 권한이 있는지도 별도로 확인한다.
고정한 revision에서는 다음 경로를 inventory한다.
plugin.json
skills/*/SKILL.md
skills/*/scripts/**
skills/*/references/**
skills/*/assets/**
mcp.json
com.github.copilot/**
agents/**
commands/**
rules/**
hooks.json
hooks/**
scripts/**
.github/copilot-instructions.md
.github/instructions/**/*.instructions.md
AGENTS.md
CLAUDE.md
이 목록은 파일이 존재하면 곧바로 위험하다는 판정표가 아니다. 무엇을 다음 단계에서 읽어야 하는지 찾는 목록이다. SKILL.md가 references나 scripts를 가리키면 참조를 끝까지 따라가고, interpreter·dependency·입출력·network 사용을 적는다. 열어볼 수 없는 generated binary, 외부 downloader, 숨은 submodule이 남거나 symlink·junction이 plugin root 밖을 가리키면 승인하지 않는다.
공식 agentplugins/agent-plugins-example의 2026년 8월 14일 tree에는 plugin.json, migration skill과 references가 있었고 mcp.json, hooks, scripts, com.github.copilot/, 저장소 instructions는 없었다. 이 예제는 패키지 구조를 읽는 데는 쓸 수 있지만 MCP나 hook 권한 검토를 대신하는 표본은 아니다.
플러그인 지침과 대상 저장소 지침을 한 장에서 대조한다
Agent Skill은 문서 묶음으로만 취급할 수 없다. 공식 Agent Skills 사양은 scripts/를 agent가 실행할 수 있는 code로 정의한다. 각 SKILL.md, rule, agent, command에서 요구하는 행동을 읽기, 쓰기, 삭제, command 실행, network 요청, secret 접근, PR·issue·deployment 변경 같은 동사로 바꾸고 대상 path·host·repository를 붙인다. “도구를 사용한다”처럼 scope가 없는 지침은 구체화되기 전까지 보류 대상이다.
플러그인을 사용할 저장소도 함께 살펴야 한다. GitHub repository custom instructions 문서 기준으로 AGENTS.md는 저장소 여러 위치에 존재할 수 있고 작업 경로에 가장 가까운 파일이 우선한다. repository-wide .github/copilot-instructions.md와 path-specific .github/instructions/**/*.instructions.md도 요청에 함께 적용될 수 있다. 플러그인 지침만 승인해도 실제 세션에서는 저장소 지침이 추가되므로, 양쪽의 허용·금지 동작이 충돌하지 않는지 확인해야 한다.
승인 가능한 상태는 지침별 동작과 대상이 설명되고, 가장 가까운 AGENTS.md까지 포함한 적용 결과가 예측되는 경우다. 지침끼리 쓰기 범위나 command 허용 여부가 충돌하거나 실패 시 중지 조건이 없다면 설치보다 지침 정리가 먼저다.
MCP와 hooks는 별도의 실행 코드로 심사한다
mcp.json의 stdio entry는 executable을 시작할 수 있다. 각 server의 type, command, args, env, cwd, url, headers를 확인한다. package에 포함된 실행 파일이라면 ./로 시작하는 plugin-relative command인지 보고, bare command라면 client별 PATH 해석과 실제 executable provenance를 설명할 수 있어야 한다.
정적 비교는 2026년 8월 14일 KST, Linux 7.0.0-1009-aws x86_64에서 수행했다. 선행 조건은 Bash와 jq 1.7이다. 아래 원문은 별도 파일을 만들지 않고 두 fixture를 같은 검사식에 넣으며, 실제 실행 파일은 시작하지 않는다.
set +e
for fixture_case in before_invalid after_fixed; do
if [ "$fixture_case" = before_invalid ]; then
fixture='{"mcpServers":{"audit":{"type":"stdio","command":"../bin/audit"}}}'
else
fixture='{"mcpServers":{"audit":{"type":"stdio","command":"./bin/audit"}}}'
fi
output=$(printf '%s\n' "$fixture" | jq -ce '
[.mcpServers[]
| select(.type == "stdio")
| .command] as $commands
| if ($commands | all(
type == "string"
and test("^[^[:space:]]+$")
and ((startswith("./") and (contains("../") | not)) or ((startswith("/") | not) and (contains("/") | not)))
))
then {status:"PASS",reason:"checked stdio command boundary"}
else {status:"FAIL",reason:"stdio command escapes plugin root or is not one token"}
end
')
if [ "$(printf '%s\n' "$output" | jq -r '.status')" = PASS ]; then
fixture_exit=0
else
fixture_exit=1
fi
printf 'case=%s input=%s\n' "$fixture_case" "$fixture"
printf 'output=%s\n' "$output"
printf 'exit=%s\n' "$fixture_exit"
done
같은 환경에서 관측한 입력·출력과 각 fixture의 판정 상태는 다음과 같다.
case=before_invalid input={"mcpServers":{"audit":{"type":"stdio","command":"../bin/audit"}}}
output={"status":"FAIL","reason":"stdio command escapes plugin root or is not one token"}
exit=1
case=after_fixed input={"mcpServers":{"audit":{"type":"stdio","command":"./bin/audit"}}}
output={"status":"PASS","reason":"checked stdio command boundary"}
exit=0
여기서 exit=는 루프 전체 프로세스의 종료 코드가 아니라 각 fixture의 판정 상태다. ../bin/audit는 1, ./bin/audit는 0이었다. 이 결과는 사양의 plugin root 포함 규칙과 일치하지만 실행 파일 내용, symlink resolution, network, headers, env, sandbox 또는 Copilot 설치 성공을 검증하지 않는다. 그러므로 두 번째 결과만으로 설치를 승인하면 안 된다.
원격 MCP는 HTTPS 여부만 보지 않는다. hostname, path, redirect, 전송 데이터 종류를 확인한다. env와 HTTP headers는 비밀 저장 수단이 아니므로 token·password·private key가 직접 들어 있으면 보류한다. ${PLUGIN_DATA}는 update 뒤에도 유지되는 writable directory이므로 생성 파일과 cache, uninstall 때 남을 수 있는 state도 검토 대상이다.
hook은 event, matcher, 실제 command와 script를 이어서 읽는다. VS Code Agent Plugins 문서는 plugin MCP와 hook이 machine에서 code를 실행할 수 있다고 경고하며, plugin MCP는 설치 때 묵시적으로 신뢰된다고 설명한다. 현재 Claude compatibility matcher 값은 parsing되지만 무시될 수 있어 matching event마다 hook이 실행될 수 있다. matcher가 범위를 좁힌다는 가정에 기대지 말고 실제 event와 변경 path를 승인 목록에 대응시킨다.
조직 설정은 파일 하나가 아니라 effective policy로 판정한다
조직 정책에서는 네 설정이 서로 다른 일을 한다. 각 기본값과 적용 범위는 Enterprise managed settings reference를 기준으로 확인한다.
enabledPlugins는 특정 marketplace의 plugin 자동 활성화 또는 차단을 다룬다.strictKnownMarketplaces는 설치 가능한 marketplace를 제한한다. 빈 배열은 marketplace 전체 잠금이다.allowedMcpServers와deniedMcpServers는 MCP server를 URL·command·name으로 허용하거나 차단하며 deny가 우선한다.permissions.disableBypassPermissionsMode와sandbox는 우회 승인, command, filesystem, network, credentials, local MCP/LSP 제한을 다룬다.
특히 allowedMcpServers 키를 생략하면 deny rule에 걸리지 않는 server가 허용되지만, 빈 allowlist는 built-in default server 외 server를 차단한다. 키 없음과 빈 배열을 모두 “미설정”으로 읽으면 정반대의 결과가 날 수 있다.
enterprise 파일 하나만 확인해도 충분하지 않다. Enterprise managed settings 구성 문서에 따르면 team의 enabledPlugins와 extraKnownMarketplaces는 baseline에 additive로 합쳐질 수 있고, private plugin은 실제 사용자의 source 접근권한도 필요하다. 해당 사용자의 team membership, MDM 또는 file-based 설정, server-managed setting과 cache 상태까지 반영한 최종 값을 플러그인이 요구하는 MCP·hook·network 범위와 대조한다. marketplace 제한, MCP 제한, bypass 금지, sandbox는 서로 대체하지 않는다.
다음 중 하나라도 남으면 설치를 보류한다
- source repository, publisher, plugin path, immutable revision을 모두 식별하지 못했다.
- symlink·junction·
../가 package path를 plugin root 밖으로 보낸다. SKILL.md가 참조하는 script·reference를 열 수 없거나 binary provenance가 불명확하다.- stdio MCP가 설명되지 않은 executable이나 shell wrapper를 시작한다.
- 원격 MCP의 endpoint·redirect·전송 데이터 범위를 설명할 수 없다.
- package의
env또는 HTTPheaders에 자격증명이 직접 들어 있다. - lifecycle hook의 event·command·변경 path가 승인 목록과 대응하지 않는다.
- 대상 저장소의 가장 가까운
AGENTS.md와 repository-wide 또는 path-specific instructions가 충돌한다. - marketplace, MCP allow/deny, bypass 금지, sandbox의 effective configuration을 확인하지 못했다.
- private plugin source에 실제 사용자의 read authorization이 없다.
- 클라이언트별 구성요소 지원 차이를 확인하지 않고 모든 client가 같다고 전제한다.
마지막 항목은 현재 문서 충돌 때문에 특히 중요하다. 2026년 8월 12일 GitHub Changelog는 com.github.copilot/ 아래 custom agents·commands·rules·hooks를 VS Code, Copilot CLI, Copilot app이 읽는다고 설명한다. 반면 현재 VS Code Agent Plugins 문서는 Agent Plugins 1.0의 client extension directory를 무시하고 portable skills와 MCP만 읽는다고 설명한다. 배포 시점이나 client version 차이일 수 있지만 공식 자료만으로 확정할 수 없으므로, 설치 대상 버전에서 component inventory로 확인해야 한다.
제한된 시험 설치의 성공과 되돌리기 기준
정적 검토를 통과했다면 data-free test repository에서만 활성화한다. network는 승인 host, filesystem은 test workspace와 disposable plugin data, credential은 none 또는 test-only로 제한한다. 예상한 skills·agents·commands만 나타나는지, 승인한 MCP만 시작하는지, hook이 문서화한 event와 path에서만 동작하는지, 저장소 instructions가 기대한 scope로 적용되는지 확인한다. 이 단계는 이번 리서치에서 직접 실행하지 않았으므로 client별 실제 결과는 후속 검증 항목이다.
예상 밖 component나 connection이 하나라도 나타나면 먼저 plugin을 disable한다. VS Code 문서상 disable은 skills, agents, hooks, MCP servers, slash commands를 비활성화하고 MCP server를 중지한다. source revision과 관측 log를 보존한 뒤 uninstall하며, enabledPlugins로 자동 설치했다면 선언형 설정도 함께 검토해야 재활성화를 막을 수 있다.
uninstall을 state 삭제와 같은 뜻으로 봐서는 안 된다. ${PLUGIN_DATA}는 update 사이에 보존되며 uninstall 시 client가 삭제할 수도 있는 directory로 정의돼 있어, 반드시 지워진다고 단정할 수 없다. 민감 데이터를 쓰지 않는 시험으로 시작하고 client별 data retention을 따로 확인해야 한다.
이 점검표의 채택 조건은 path test 통과가 아니다. 고정된 source, 모든 지침과 실행 파일, MCP와 hooks, 대상 저장소 instructions, effective policy를 설명할 수 있고 제한된 client test까지 예상대로 끝난 경우에만 범위를 넓힌다. 조직 전체 검토로 이어가려면 GitHub Copilot 보안 검토 단계에서 저장소 밖의 정책과 운영 통제를 함께 확인할 수 있다.