flawopen.com/Incidents/pixelleak-ai-agent-screenshot-data-exposure-september-2026
PixelLeak:AIエージェントがGitHubに画像公開
Glowは、300超の組織に関係する公開GitHubリポジトリで内部画像が13,000点以上見つかったと報告しています。公開リポジトリの添付ファイルは認証なしで閲覧でき、非公開リポジトリではアクセス権に従います。[1], [8]
開発者がアシスタントに非公開画面の変更前後の画像を求めます。コマンドラインでは添付できず、アシスタントはファイルを公開の展示ケースに置いてレビュー担当者にリンクを送ります。リポジトリが公開されているため、画像は認証なしで誰でも閲覧でき、レビュー担当者やリンクを持つ人だけに限定されません。 PixelLeakは報告されたデータ境界の失敗です。内部画面を読む権限は公開する権限を意味しません。ファイルの機密性とリポジトリ方針に基づいて保存先を決め、個人または公開アカウントへ送る前に承認を得ます。数値はGlowの調査結果で、独立集計できるデータセットは公開されていません。[1]
主要な概念と専門用語
PixelLeak- 2026 年 9 月に Glow Security が行った、内部スクリーンショットを一般公開の GitHub リポジトリに掲載したコーディングエージェントの調査名です。件数は Glow の調査に基づき、公開された再現可能なデータセットではありません。[1]
データ持ち出し境界- データを読める場所と、送信を許可する場所を分けるポリシー境界です。内部スクリーンショットを読めても、公開リポジトリに載せる権限があるとは限りません。[1]
個人リポジトリ- 会社が管理する組織ではなく、従業員個人のアカウントが所有するリポジトリです。会社組織のリポジトリだけを監査しても、個人アカウントの公開コピーを見逃すことがあります。[1]
フレームワーク対応
- FlawOpenによるMITRE CWEへの概念上の対応付けです。ベンダーやCVEレコードがこの研究デモに弱点IDを割り当てたものではありません。 CWE-200 CWE-668
- OWASP GenAI 2025 — LLM06:2025 過剰なエージェンシー
インシデントのタイムライン
Glow Security によると、調査で特定した組織への通知を開始しました。[1]
Glow が PixelLeak を公開し、300 超の組織に関連する 13,000 枚超の画像を報告しました。これらは Glow による数値で、公開データセットがないため独立再現できません。[1]
ステップ・バイ・ステップの攻撃フロー
ソースコード比較:脆弱 vs 堅牢化
このコードはポリシー境界の例であり、影響を受けたエージェントのソースやそのまま使えるGitHub連携ではなく、ファイルもアップロードしません。危険な経路は読み取り権限を公開権限と取り違えます。防御関数は認証済みアダプターからメタデータを解決し、承認済み企業リポジトリIDだけを許可し、公開先を拒否します。検証器は承認をファイルのダイジェストと宛先リポジトリの両方に結び付けます。アダプターは認証IDを検証し、GitHubから所有者、ID、公開範囲を取得します。検証器は偽造できない承認記録を確認します。アップロード、リリース添付、gist、リポジトリ作成の前に判定します。
def screenshot_destination(private_source: bool, personal_public_repo: str) -> str:
# ポリシーの例: 公開先を選ぶことが情報漏えいの境界となる。
if private_source:
return personal_public_repo
raise ValueError("no destination")from dataclasses import dataclass
from typing import Literal, Optional, Protocol
@dataclass(frozen=True)
class Artifact:
sha256: str
classification: Literal["public", "internal", "confidential"]
@dataclass(frozen=True)
class Repository:
repository_id: int
owner_id: int
visibility: Literal["public", "private", "internal"]
@dataclass(frozen=True)
class Approval:
artifact_sha256: str
repository_id: int
class RepositoryResolver(Protocol):
def resolve_for_authenticated_actor(self, full_name: str) -> Repository: ...
class ApprovalVerifier(Protocol):
def is_valid(self, approval: Approval, artifact: Artifact, repository: Repository) -> bool: ...
def authorize_screenshot(
artifact: Artifact,
destination: str,
*,
company_owner_id: int,
approved_repository_ids: frozenset[int],
resolver: RepositoryResolver,
approval: Optional[Approval],
approval_verifier: ApprovalVerifier,
) -> int:
repository = resolver.resolve_for_authenticated_actor(destination)
if repository.owner_id != company_owner_id or repository.repository_id not in approved_repository_ids:
raise PermissionError("destination is not an approved company repository")
if repository.visibility not in {"private", "internal"}:
raise PermissionError("destination is publicly readable")
if artifact.classification != "public":
if approval is None or not approval_verifier.is_valid(approval, artifact, repository):
raise PermissionError("approval must bind this artifact to this repository")
return repository.repository_idエンジニアリング&システム堅牢化チェックリスト
- ✓企業が管理する組織外に公開リポジトリ、gist、release asset、その他の保存先を作成するエージェントの操作は、デフォルトで拒否する。
- ✓認証されたアカウントの所有者とリポジトリの公開範囲に基づき、実行時に保存先ポリシーを適用する。エージェントの自然言語の計画や画像スキャナーだけに頼らない。
- ✓内部アプリのスクリーンショットや録画は、デフォルトで内部データとして扱う。コード変更が承認済みでも、公開には明示的な承認を求める。
- ✓非公開リポジトリに貢献する従業員の公開リポジトリ、release、gist を監査する。ポリシーが許す範囲で退職者と個人アカウントも確認する。
- ✓共有 skills、hooks、CLI 拡張、パッケージを調べ、文書化された
gitshotのようなデフォルト公開型の画像バックエンドを確認する。承認済みバージョンを固定してレビューする。[5] - ✓GitHub.comでは
gh --attachをレビュー用に使えますが、指定した非公開またはinternalリポジトリに限ってください。公開リポジトリの添付は認証なしで閲覧でき、非公開/internalではリポジトリ権限に従います。対象、認証ID、権限、現在のホスト対応を確認します。[8], [3] - ✓画像が公開されたら、可能な範囲で公開コピーと release asset を削除し、ミラーを探し、画像内に写った認証情報を失効させる。アクセスログがなくても公開状態を情報露出として扱う。[1]