扫描技能是否存在安全问题

借助 Agent Registry,您可以为独立技能配置自动安全扫描,使用 Organization Policy Service 在整个组织中强制执行扫描政策,并对安全发现结果进行分类,从而防止受损技能影响您的智能体。

当您上传技能修订版本时,Agent Registry 会扫描 SKILL.md 指令文件、可选脚本和支持资源,以查找未经授权的数据渗漏、凭据泄露和提示词注入等安全风险。

技能安全扫描使用大语言模型 (LLM) 来评估指令、代码逻辑和语义意图。由于 LLM 分析是概率性的,因此扫描可能会产生假正例或假负例,并且不同运行的结果可能会有所不同。此外,有关发现结果的详细信息可能只是近似值,并且可能会出现幻觉。开发者必须先查看并验证扫描结果,然后才能应用修复更改。

准备工作

  1. 设置 Agent Registry。
  2. 对于单项目设置,请获取已启用 Agent Registry 的治理项目的项目 ID。如果您为多个项目配置了管理边界,请使用管理项目的 ID 进行边界范围内的发现和注册,或指定成员项目 ID 进行单项目操作。

  3. 在 Agent Registry 中注册独立技能。

  4. 如需使用本文档中的 Google Cloud CLI 命令,请设置 gcloud CLI 环境。

所需的角色

如需获得在 Agent Registry 中配置扫描和分类发现结果所需的权限,请让管理员向您授予已启用 Agent Registry 的治理项目的以下 IAM 角色:

如需详细了解如何授予角色,请参阅管理对项目、文件夹和组织的访问权限。

您也可以通过自定义角色或其他预定义角色来获取所需的权限。

其他 Agent Registry 角色也可能包含配置扫描和查看技能所需的权限。如需了解详情,请参阅 Agent Registry 角色和权限。

未压缩载荷大小限制

为确保最佳性能并适应底层 LLM 扫描器的处理词元限制,Agent Registry 会在扫描处于活跃状态时强制执行严格的未压缩大小限制:

  • 解压后的 skill 总大小:解压后的归档文件大小上限为 10 MB。
  • 每个文件的解压缩大小:技能包中任何单个文件的大小上限为 1 MB。

如果某项技能启用了扫描,并且超出了这些限制,则创建技能修订版本会失败,并显示 INVALID_ARGUMENT 错误,或者修订版本的扫描状态会解析为 UNSUPPORTED_FORMAT。

如果明确停用了扫描,Agent Registry 会绕过这些特定于扫描的大小限制,但一般系统限制仍然适用。如需详细了解系统限制,请参阅配额和系统限制。

为技能配置扫描政策

默认情况下,技能使用已启用(屏蔽) (ENABLED_BLOCKING) 扫描政策,该政策会自动扫描上传的技能修订版本是否存在安全风险,例如未经授权的数据渗漏、凭据泄露和提示词注入。检测到的问题会在治理项目 projects/PROJECT_NUMBER/locations/LOCATION/findings/FINDING_ID 中公开为只读 Finding 资源。

如果选择已启用(屏蔽),Agent Registry 会阻止下载存在安全发现结果的修订版本,并阻止将存在发现结果或待扫描的修订版本提升为技能的默认修订版本。

您还可以为非屏蔽审核模式 (ENABLED_NONBLOCKING) 配置扫描政策,或停用扫描 (DISABLED)。如需详细了解支持的扫描政策,请参阅扫描政策。

设置或更新技能扫描设置

对现有技能启用或更新扫描功能仅适用于在配置更改后创建的技能修订版本。系统不会针对已创建的修订版本追溯触发扫描。如需扫描在扫描功能停用期间上传的技能内容,您必须创建新的技能修订版本。

如需在创建或更新技能时配置扫描设置,请按以下步骤操作:

控制台

  1. 在 Google Cloud 控制台中,前往 Agent Registry 页面:

    前往 Agent Registry

  2. 选择技能标签页。

  3. 点击添加技能,或选择现有技能,然后点击 修改。

  4. 在安全扫描部分中,选择所需的扫描政策。

  5. 点击保存或创建。

gcloud

  • 创建启用了扫描(屏蔽)的技能:运行 gcloud agent-registry skills create 命令,并将 --scanning-policy 标志设置为 enabled-blocking。例如,如果您使用 Cloud Storage 存储桶中的 ZIP 归档文件注册技能:

    gcloud agent-registry skills create SKILL_ID \
        --project=PROJECT_ID \
        --location=LOCATION \
        --target-state=disabled \
        --scanning-policy=enabled-blocking \
        --gcs-source-uri="gs://BUCKET_NAME/SKILL_PACKAGE.zip"
    
  • 创建启用了扫描功能的技能(非屏蔽):运行 gcloud agent-registry skills create 命令,并将 --scanning-policy 标志设置为 enabled-nonblocking。例如,如果您使用 Cloud Storage 存储桶中的 ZIP 归档文件注册技能:

    gcloud agent-registry skills create SKILL_ID \
        --project=PROJECT_ID \
        --location=LOCATION \
        --target-state=disabled \
        --scanning-policy=enabled-nonblocking \
        --gcs-source-uri="gs://BUCKET_NAME/SKILL_PACKAGE.zip"
    
  • 更新现有技能的扫描政策:运行 gcloud agent-registry skills update 命令,并将 --scanning-policy 标志设置为所选政策,例如 enabled-nonblocking:

    gcloud agent-registry skills update SKILL_ID \
        --project=PROJECT_ID \
        --location=LOCATION \
        --scanning-policy=enabled-nonblocking
    
  • 停用对技能的扫描:运行 gcloud agent-registry skills update 命令,并将 --scanning-policy 标志设置为 disabled:

    gcloud agent-registry skills update SKILL_ID \
        --project=PROJECT_ID \
        --location=LOCATION \
        --scanning-policy=disabled
    
  • 描述现有技能的扫描配置:运行 gcloud agent-registry skills describe 命令,并将 --format 标志设置为 value(scanningConfig.policy):

    gcloud agent-registry skills describe SKILL_ID \
        --project=PROJECT_ID \
        --location=LOCATION \
        --format="value(scanningConfig.policy)"
    

替换以下内容:

  • SKILL_ID:技能的 ID。更新或描述现有的手动注册技能时,请添加 private- 前缀,例如 private-my-skill。
  • PROJECT_ID:项目 ID。
  • LOCATION:注册表位置。
  • BUCKET_NAME:包含 ZIP 软件包的 Cloud Storage 存储桶名称。在从存储桶导入之前,请确保 Agent Registry 服务代理对该存储桶具有 storage.objects.get 权限。如需了解详情,请参阅注册技能。
  • SKILL_PACKAGE:包含技能载荷的技能包的名称。

REST

如需使用 REST API 配置扫描,请在请求正文中添加 scanningConfig 对象:

curl -X PATCH \
    -H "Authorization: Bearer $(gcloud auth print-access-token)" \
    -H "Content-Type: application/json" \
    -d '{
        "scanningConfig": {
          "policy": "ENABLED_BLOCKING"
        }
      }' \
    "https://agentregistry.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/skills/SKILL_ID?updateMask=scanningConfig"

替换以下内容:

  • PROJECT_ID:项目 ID。
  • LOCATION:注册表位置。
  • SKILL_ID:技能的 ID。对于手动注册的技能,请添加 private- 前缀,例如 private-my-skill。

使用 Organization Policy Service 强制执行扫描

您可以在评估扫描政策的 Skill 资源上定义自定义 Organization Policy Service 限制条件,从而强制执行组织级扫描政策,并可选择豁免 Resource Manager 标记。

如需了解 Agent Registry 中的组织政策强制执行、功能和限制,请参阅组织政策强制执行。

定义自定义限制条件

创建一个名为 skills-scan-constraint.yaml 的 YAML 文件,其中包含以下规范:

name: organizations/ORGANIZATION_ID/customConstraints/custom.skillsScanningEnforcement
resourceTypes:
- agentregistry.googleapis.com/Skill
methodTypes:
- CREATE
- UPDATE
condition: resource.scanningConfig.policy == "DISABLED"
actionType: DENY
displayName: Prevent Disabling Skills Scanning
description: Prevents creating or updating skills with scanning disabled.

将 ORGANIZATION_ID 替换为您的数字组织 ID。

如需在所有技能中强制执行屏蔽模式,并阻止 DISABLED 和 ENABLED_NONBLOCKING 扫描政策,您也可以设置 condition: resource.scanningConfig.policy == "ENABLED_BLOCKING" 和 actionType: ALLOW。

设置自定义限制条件

使用 gcloud org-policies set-custom-constraint 命令在组织中上传并注册自定义限制条件:

gcloud org-policies set-custom-constraint skills-scan-constraint.yaml

应用具有条件豁免的政策

创建一个名为 skills-scan-policy.yaml 的政策定义文件,该文件在所有标准项目中强制执行限制条件,同时豁免您使用 exempt-scanning-enforcement: true 标记的测试项目:

name: organizations/ORGANIZATION_ID/policies/custom.skillsScanningEnforcement
spec:
  rules:
  # Enforce scanning on all standard projects
  - enforce: true
    condition:
      expression: "!resource.matchTag('ORGANIZATION_ID/exempt-scanning-enforcement', 'true')"
      title: "Enforce Scanning"
      description: "Enforce scanning on all non-exempt projects"
  # Bypass enforcement for tagged projects
  - enforce: false
    condition:
      expression: "resource.matchTag('ORGANIZATION_ID/exempt-scanning-enforcement', 'true')"
      title: "Exempt Testing Projects"
      description: "Allow scanning to be disabled for testing projects"

将 ORGANIZATION_ID 替换为您的数字组织 ID。

使用 gcloud org-policies set-policy 命令将政策应用于您的组织:

gcloud org-policies set-policy skills-scan-policy.yaml

验证政策

使用 gcloud org-policies describe 命令验证政策在项目上是否有效:

gcloud org-policies describe custom.skillsScanningEnforcement \
    --project=PROJECT_ID \
    --effective

将 PROJECT_ID 替换为您的项目 ID。

查看扫描结果和修订状态

发布技能修订版本时,扫描工具会在后台异步运行。如需检查修订版本元数据并验证扫描结果,请运行 gcloud agent-registry skills revisions describe 命令:

gcloud agent-registry skills revisions describe REVISION_ID \
    --skill=SKILL_ID \
    --project=PROJECT_ID \
    --location=LOCATION

替换以下内容:

  • REVISION_ID:技能修订版本的 ID。
  • SKILL_ID:技能容器的 ID。对于手动注册的技能,请添加 private- 前缀,例如 private-my-skill。
  • PROJECT_ID:项目 ID。
  • LOCATION:注册表位置。

输出包含类似于以下示例的 scanResult 块:

name: projects/my-project/locations/us-central1/skills/private-my-skill/revisions/rev-v1
createTime: '2026-08-10T09:15:00.000000Z'
state: ACTIVE
scanResult:
  scanState: SUCCEEDED
  scanTime: '2026-08-10T09:16:22.000000Z'
  findings:
  - projects/my-project/locations/us-central1/findings/b9a8c7d6-e5f4-4321-89ab-cdef01234567

可能的 scanResult.scanState 值如下:

  • SUCCEEDED:扫描已完成执行。如果检测到安全问题,其资源名称会列在 scanResult.findings 数组中。如果未检测到任何问题,scanResult.findings 为空。
  • RUNNING:扫描正在执行。
  • DISABLED:由于在创建技能修订版本时技能的扫描政策设置为 DISABLED,因此会绕过扫描。
  • UNSUPPORTED_FORMAT:扫描器无法分析上传的归档文件,例如,因为其未压缩大小超出了扫描限制,或者其归档格式不受支持。scanResult.errorMessage 中提供了详细信息。
  • FAILED:由于内部错误,扫描无法完成。scanResult.errorMessage中提供了详细信息。

修订版本的扫描状态反映了创建修订版本时处于有效状态的扫描配置。为技能启用或更新扫描功能仅适用于在更改后创建的修订版本,不会追溯性地触发对现有修订版本的扫描。如需扫描在扫描功能停用时上传的技能内容,您必须创建新的技能修订版本。

对安全发现结果进行分类

当扫描检测到安全问题时,详细的遥测数据会作为 Finding 资源发布到 Agent Registry,这些资源的作用域限定为您的项目和位置。查看发现结果需要 Agent Registry API Admin (roles/agentregistry.admin) 角色。

  • 列出技能修订版本的所有发现结果:运行 gcloud agent-registry findings list 命令:

    gcloud agent-registry findings list \
        --project=PROJECT_ID \
        --location=LOCATION \
        --filter="resource=\"projects/PROJECT_ID/locations/LOCATION/skills/SKILL_ID/revisions/REVISION_ID\""
    

    替换以下内容:

    • PROJECT_ID:项目 ID。
    • LOCATION:注册表位置。
    • SKILL_ID:技能容器的 ID,例如 private-my-skill。
    • REVISION_ID:技能修订版本的 ID。

    输出类似于以下内容:

    NAME                                                                                  SEVERITY           FINDING_CLASS  CREATE_TIME
    projects/my-project/locations/us-central1/findings/FINDING_ID  SEVERITY_CRITICAL  VULNERABILITY  2026-08-10T09:16:22.104Z
    
  • 描述发现结果详情:运行 gcloud agent-registry findings describe 命令:

    gcloud agent-registry findings describe FINDING_ID \
        --project=PROJECT_ID \
        --location=LOCATION \
        --format=json
    

    替换以下内容:

    • FINDING_ID:Finding 资源的 ID。
    • PROJECT_ID:项目 ID。
    • LOCATION:注册表位置。

    发现结果输出示例:

    {
      "name": "projects/my-project/locations/us-central1/findings/FINDING_ID",
      "uid": "FINDING_ID",
      "createTime": "2026-08-10T09:16:22.104Z",
      "updateTime": "2026-08-10T09:16:22.104Z",
      "resource": "projects/my-project/locations/us-central1/skills/private-my-skill/revisions/rev-v1",
      "severity": "SEVERITY_CRITICAL",
      "findingClass": "VULNERABILITY",
      "files": [
        {
          "path": "resources/helper.py",
          "lineNumber": "12"
        }
      ],
      "detail": "Involves unauthorized outbound network requests transmitting sensitive local files or environment variables. Detected inside resources/helper.py at line 12."
    }
    

    每个 Finding 资源都包含以下关键字段:

    • resource:与发现结果关联的技能修订版本的完整资源名称。
    • severity:严重级别。允许的值有:
      • SEVERITY_CRITICAL
      • SEVERITY_HIGH
      • SEVERITY_MEDIUM
      • SEVERITY_LOW
      • SEVERITY_UNSPECIFIED
    • findingClass:发现结果的类型:
      • VULNERABILITY:软件或指令缺陷。
      • SECRET:泄露的明文凭证、密钥或令牌。
    • files:技能归档中受影响文件的列表,包括相对 path 和 lineNumber。值为 0 表示发现结果适用于整个文件。
    • detail:对检测到的安全问题的详细说明。

修复发现结果并更新技能

如需解决技能的安全发现结果,请按照以下步骤操作:

  1. 查看发现结果的 detail 字段,并检查 files 数组中的违规文件 path 和 lineNumber。由于自动扫描使用 LLM 检查语义代码和指令,因此请在修改文件之前验证报告的行号和发现结果。
  2. 在本地开发环境中更新源文件,以解决发现结果。例如,移除未经授权的网络调用、移除暴露的凭据或消除提示词注入模式。
  3. 将更新后的文件打包到新的 ZIP 归档文件中。
  4. 创建新的技能修订版本。
  5. 验证新修订版本的 scanResult.scanState 是否解析为 SUCCEEDED,且未列出任何发现结果。
  6. 更新 skill 的默认修订版本,使其指向经过验证的修订版本。

后续步骤