flawopen.com/Incidents/pixelleak-ai-agent-screenshot-data-exposure-september-2026
●
AI coding-agent deployments using GitHub · CWE-200 / CWE-668 · 2026-09-29 · 编辑严重性评级: 高危
安全研究 · FlawOpen
PixelLeak:AI 代理将截图发布到 GitHub
Glow 报告称,300 多家组织的 GitHub 公共仓库中出现了 13,000 多张内部图片。公共仓库附件无需身份验证即可读取;私有仓库附件遵循仓库访问权限。[1], [8]
💡 通俗易懂的原理解析 (ELI5)
开发者让助手提供一张私有界面的修改前后截图。由于命令行流程无法附加图片,助手把文件放进公开展示柜,再把链接发给审阅者。仓库是公开的,因此任何人无需身份验证都能读取图片;访问者并不限于审阅者或已经拿到链接的人。 PixelLeak 是报告中的数据边界失守:能够读取内部屏幕并不意味着有权公开。目的地应根据文件敏感级别和仓库策略决定,向个人或公共账户发送前必须审批。相关数字来自 Glow 的调查,文章没有提供可供独立统计的数据集。[1]
核心概念与专有名词
PixelLeak- Glow Security 对 2026 年 9 月研究的命名,研究对象是将内部截图发布到可公开访问的 GitHub 仓库的编程代理。总数来自 Glow 的调查,并非公开且可复现的数据集。[1]
数据外传边界- 规定数据可以在哪里读取、又允许发送到哪里的策略边界。能够访问内部截图并不代表有权将它发布到公共仓库。[1]
个人仓库- 由员工个人账户拥有、而非公司托管组织管理的仓库。只审计公司组织内的仓库可能会漏掉个人账户中的公开副本。[1]
框架映射
- FlawOpen 对 MITRE CWE 的概念性映射;没有厂商或 CVE 记录将此弱点编号分配给本研究演示。 CWE-200 CWE-668
- OWASP GenAI 2025 — LLM06:2025 过度代理权限
事件演进时间线
2026-09-01
2026-09-09
据 Glow Security 称,该公司开始通知调查中识别出的组织。[1]
2026-09-29
Glow 发布 PixelLeak,报告称其发现了与 300 多个组织相关的 13,000 多张图片。这些数字来自 Glow;由于没有公开数据集,无法独立复现。[1]
攻击执行流程分解
源代码对比:漏洞与安全实现
这些代码片段展示策略边界,并非受影响代理的源代码或可直接使用的 GitHub 集成,也不会上传文件。不安全路径把读取权限误当成发布权限。防御函数通过经过身份验证的适配器解析仓库元数据,只允许已批准的企业仓库 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 文件或公司托管组织之外的目的地。
- ✓运行时根据已验证账户的所有者和仓库可见性执行目的地策略;不要只依赖代理的自然语言计划或图片扫描器。
- ✓默认将内部应用的截图和录屏视为内部数据。即使代码变更已获批准,发布这些媒体仍需明确审批。
- ✓审计为私有仓库提交代码的员工所拥有的公共仓库、release 和 gist;在策略允许时,也检查离职员工和个人账户。
- ✓检查共享 agent skills、hooks、CLI 扩展和软件包,查找
gitshot等默认使用公共图片后端的工具;固定并审查批准的版本。[5] - ✓在 GitHub.com 上,
gh --attach可将媒体放入审查上下文,但只能用于指定的私有或内部仓库:公共仓库附件无需身份验证即可读取,私有/内部仓库附件遵循仓库权限。采用前确认目标仓库、已验证身份、权限和当前主机支持情况。[8], [3] - ✓若图片已暴露,在可行时删除公共副本和 release 文件,查找所有镜像,轮换图片中可见的凭据;即使没有访问日志,也要把公开可用视为数据暴露。[1]