0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Claude Code archiveプラグイン、sha256改ざん検知を実機で確認

0
Posted at

TL;DR

  • Claude Code v2.1.224 で archive プラグインソースが追加され、git・npm を使わず HTTPS 上の zip からプラグインをインストールできるようになりました。
  • 実際に Cloudflare R2 へ公開 HTTPS で zip を置き、marketplace.jsonarchive ソースを書いて claude plugin install を実行したところ、git リポジトリなしで正常にインストールできました。
  • sha256 を意図的に誤らせると Plugin archive integrity check failedインストールが止まる、URL を http:// にすると must use https:// でそもそも受け付けない、という2つの拒否挙動も実機で確認しました。

はじめに

対象読者は、Claude Code のプラグイン配布を CI や社内配布パイプラインに組み込みたい開発者・運用者です。プラグインを配るとき、これまでは git リポジトリか npm パッケージのどちらかを用意する必要がありました。社内に GitHub がない・npm レジストリを公開したくない、といった事情があると地味に面倒です。v2.1.224 で追加された archive ソースは、この制約を「HTTPS で zip を配れればいい」まで下げます。本記事では実際に Cloudflare R2 に zip を置いてインストールを試し、公式ドキュメントが説明しているセキュリティ制約(HTTPS 必須・sha256 ピン留め)が実際にどう働くかを確認しました。

archiveプラグインソースとは

公式changelogによると、v2.1.224(2026-08-07公開)で以下が追加されています。

Added archive plugin source: install plugins from a zip over HTTPS without git or npm, with optional SHA-256 pinning

プラグインマーケットプレイスの公式ドキュメントには、marketplace.json 内での指定形式が記載されています。

{
  "name": "my-test-plugin",
  "source": {
    "source": "archive",
    "url": "https://example.com/my-test-plugin.zip",
    "sha256": "任意: アーカイブのSHA-256(64桁16進数)"
  }
}

ドキュメントが明記している制約は次の3点です。

  • url は HTTPS 必須。http:// は拒否され、ループバック・リンクローカル・クラウドメタデータ用のホストへの接続も拒否される(リダイレクト先も同じ条件を満たす必要がある)
  • sha256 は任意だが、指定すればダウンロードのたびに検証され、不一致ならインストールを拒否する
  • アーカイブは 256MiB を超えると拒否される

ここまでは公式ドキュメントの記載内容です。実際にこの制約が機能するかを、以下で検証しました。

実機検証1: R2にzipを置いてgit無しでインストールする

まず最小構成のプラグイン(plugin.jsonSKILL.md のみ)を作り、zip化してsha256を計算しました。

$ zip -r my-test-plugin.zip my-test-plugin
$ sha256sum my-test-plugin.zip
ee702049a7b795a9e1acc341900468cddb9516a627ead64b640471a6ba99c1ba  my-test-plugin.zip

このリポジトリは記事画像の配信に Cloudflare R2 を使っており、公開HTTPSのバケットドメインを既に持っています。同じバケットの test-assets/ 配下に zip をアップロードし、公開URL経由でダウンロードできることを確認したうえで、marketplace.json を作成しました。

{
  "name": "archive-test-marketplace",
  "owner": { "name": "hourly-dispatch-verification" },
  "plugins": [
    {
      "name": "my-test-plugin",
      "source": {
        "source": "archive",
        "url": "https://pub-xxxxxxxx.r2.dev/test-assets/my-test-plugin.zip",
        "sha256": "ee702049a7b795a9e1acc341900468cddb9516a627ead64b640471a6ba99c1ba"
      }
    }
  ]
}

これをローカルディレクトリからマーケットプレイスとして登録し、インストールを実行します。

$ claude plugin marketplace add /path/to/marketplace --scope local
√ Successfully added marketplace: archive-test-marketplace (declared in local settings)

$ claude plugin install my-test-plugin@archive-test-marketplace
Installing plugin "my-test-plugin@archive-test-marketplace"...
√ Successfully installed plugin: my-test-plugin@archive-test-marketplace (scope: user)

claude plugin list にも表示され、実体は ~/.claude/plugins/cache/archive-test-marketplace/my-test-plugin に展開されていました。この間、git clone も npm install も一切発生していません。使用した Claude Code のバージョンは claude --version で確認した 2.1.226 です。

実機検証2: sha256を誤らせると止まる

同じマーケットプレイスの sha256 を意図的に別の値へ書き換え、claude plugin marketplace update で更新してから再インストールを試しました。

$ claude plugin install my-test-plugin@archive-test-marketplace
× Failed to install plugin "my-test-plugin@archive-test-marketplace":
Plugin archive integrity check failed for https://pub-xxxxxxxx.r2.dev/test-assets/my-test-plugin.zip:
expected sha256 0000000000000000000000000000000000000000000000000000000000000000,
got ee702049a7b795a9e1acc341900468cddb9516a627ead64b640471a6ba99c1ba.
The archive was not installed. Verify the sha256 in the marketplace entry, or that the URL serves the intended file.

ダウンロード自体は起きているものの、展開・インストールの前でハッシュ不一致を検出して止めています。差し替え攻撃(配布元のzipを別内容に入れ替える)に対する防御として機能することを確認できました。

実機検証3: httpスキームはそもそも拒否される

sha256 を正しい値に戻したうえで、URLのスキームだけ https:// から http:// に変更してみました。

$ claude plugin install my-test-plugin@archive-test-marketplace
× Failed to install plugin "my-test-plugin@archive-test-marketplace":
This plugin's marketplace entry is invalid: source.url: Archive URLs must use https://
and must not point at a loopback, link-local, or cloud-metadata host

こちらはダウンロードの前、マーケットプレイスエントリのバリデーション段階で弾かれます。ドキュメントに書かれていた「ループバック・リンクローカル・クラウドメタデータホストも拒否する」という記述と合わせて考えると、SSRF(サーバー側から意図しない内部ホストへリクエストさせる攻撃)対策を意識した設計だとわかります。

著者視点の一次所見

3つの検証を通して気づいたのは、archive ソースが「gitやnpmが使えない環境向けの簡易版」ではなく、むしろgit/npmソースより検証項目が明示的に多い という点です。git ソースはコミットハッシュを指定しない限り改ざん検知の仕組みを持ちませんが、archive ソースは sha256 を指定するだけでダウンロードのたびに検証されます。社内配布で「このzipは誰かが差し替えていないか」を機械的に保証したい場合、archiveソース+sha256ピン留めのほうがgitソースより検証が簡潔になる場面があります。

一方で、sha256を省略した場合は当然ながら差し替え検知は働きません。今回の検証はsha256を指定した状態のものなので、運用に組み込む際は sha256 を必ず指定する前提で設計するのが安全だと感じました。

実務での使いどころ

  • 社内向けプラグイン配布: GitHub Enterprise や npm レジストリを持たないチームでも、静的ファイルサーバー(S3・R2・Artifactory等)だけでプラグイン配布が完結する
  • 改ざん検知が必要な配布: sha256 を配布物と一緒に社内Wikiやリリースノートに載せておけば、利用者側で不一致インストールが自動的にブロックされる
  • バージョン: v2.1.224未満のClaude Codeでは動かない: 公式ドキュメントによれば v2.1.120〜v2.1.223 では専用のエラーメッセージが出て失敗し、それより古いバージョンではマーケットプレイス自体の読み込みが失敗します。導入前にチーム全員のバージョンを揃える必要があります

関連記事

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?