跳转到正文
报告库
用途分类 / 开发辅助

Golang Graphql Skill 安全审计

作者说它能做什么(原文)

Implements GraphQL APIs in Golang using gqlgen or graphql-go. Apply when building GraphQL servers, designing schemas, writing resolvers, handling subscriptions, or integrating GraphQL with existing Go HTTP services. Also apply when the codebase imports `github.com/99designs/gqlgen` or `github.com/graph-gophers/graphql-go`.

第三方安全检查结论

发现安全风险

已检查文件
5
发现的风险
5
会不会运行危险命令?检查是否下载程序后直接运行、让他人远程控制电脑,或藏起要运行的命令。发现 1 项风险
中风险

项目初始化会执行未固定版本的远程 Go 模块

原文依据:1 处
发现了什么

安装示例直接运行 `github.com/99designs/gqlgen init`,随后又使用 `@latest` 获取工具。这不是可复现的版本固定,并会执行或引入下载时最新的上游代码。

为什么需要注意

如果上游最新版本被破坏、发生不兼容变更或解析结果随时间变化,远程代码会在开发环境中执行,并可能生成文件或修改模块依赖。

项目设置指令会通过 `go run` 获取并执行 gqlgen,且命令没有指定版本;紧接着的工具安装又明确使用 `@latest`。当用户采用这些命令时,实际执行或加入项目的代码会随上游最新版本变化,影响构建可复现性并扩大供应链风险。用户可要求作者提供经过审核的固定版本和校验方式。

references/gqlgen.md:21来自说明文档打开原文件
```bash# Bootstrap a new projectgo run github.com/99designs/gqlgen init# Pin the tool in go.mod for reproducible generation (Go 1.24+)go get -tool github.com/99designs/gqlgen@latest```
会不会泄露文件和密钥?检查是否发送含密码或密钥的文件,以及代码里是否直接写了密钥。发现 1 项风险
中风险

错误清理器会原样放行所有 gqlerror,可能泄露内部详情

原文依据:3 处
发现了什么

文档称绝不应返回原始内部错误,但示例对任何能转换为 `*gqlerror.Error` 的错误直接返回,并仅清理其他错误。“已经格式化”是未经验证的假设。

为什么需要注意

如果 resolver、指令或依赖把 SQL、服务响应、路径或其他内部信息包装为 gqlerror,这些内容可能直接发送给 API 客户端。

Skill 正确警告不要向客户端返回内部错误,但示例把所有可转换为 `*gqlerror.Error` 的错误都视为“已经格式化”并原样返回,没有检查其消息或扩展是否含 SQL、栈信息、路径或其他敏感内容。如果内部组件构造了 gqlerror,该分支可能绕过统一清理。用户可要求作者只放行明确标记的安全客户端错误,并对其余错误统一替换和服务端记录。

SKILL.md:158来自说明文档打开原文件
## Error HandlingNever return raw internal errors — they leak SQL messages, stack traces, or service internals to clients.```go// gqlgen — custom ErrorPresenter strips internal detailssrv.SetErrorPresenter(func(ctx context.Context, err error) *gqlerror.Error {    var gqlErr *gqlerror.Error    if errors.As(err, &gqlErr) {        return gqlErr // already formatted    }    // log internal err here    return gqlerror.Errorf("internal error") // safe client message})
查看另外 2 个位置
references/gqlgen.md:181来自说明文档打开原文件
```gosrv.SetErrorPresenter(func(ctx context.Context, err error) *gqlerror.Error {    var gqlErr *gqlerror.Error    if errors.As(err, &gqlErr) {        return gqlErr    }    log.Ctx(ctx).Error("resolver error", "err", err)    return gqlerror.Errorf("internal server error")})
SKILL.md:160来自说明文档打开原文件
Never return raw internal errors — they leak SQL messages, stack traces, or service internals to clients.```go// gqlgen — custom ErrorPresenter strips internal detailssrv.SetErrorPresenter(func(ctx context.Context, err error) *gqlerror.Error {    var gqlErr *gqlerror.Error    if errors.As(err, &gqlErr) {        return gqlErr // already formatted    }    // log internal err here    return gqlerror.Errorf("internal error") // safe client message})
会不会删除文件或一直在后台运行?检查是否大范围删除文件、改写磁盘,或设置自动启动。未发现风险
会不会绕过安全保护?检查是否跳过网站安全验证、开放过多文件权限,或取消操作前的确认。发现 3 项风险
中风险

把 APQ 描述成查询白名单可能造成错误的生产安全判断

原文依据:3 处
发现了什么

Skill 声称 gqlgen 的 APQ 扩展可以拒绝任意查询字符串,但常规 APQ 是客户端提交并缓存查询散列的机制,并不等同于仅接受预先批准查询的静态白名单。生产示例也只启用了 APQ 缓存。

为什么需要注意

用户可能以为服务器只接受批准过的操作,实际上攻击者仍可能注册或提交新的查询;复杂度限制仍有帮助,但不能提供白名单的访问控制效果。

文档把 gqlgen 的 APQ 扩展描述为可“拒绝任意查询字符串”的生产查询白名单,但实际生产片段只配置了一个 APQ 缓存,没有展示预注册或批准哈希的机制。因此用户可能误以为该配置已限制 API 只能执行审核过的查询,并据此作出错误的公开部署决定。可要求作者区分 APQ 与真正的持久查询白名单,并展示拒绝未知查询的实现。

SKILL.md:240来自说明文档打开原文件
For graph-gophers: `graphql.MaxDepth(10)` and `graphql.MaxParallelism(10)` options at `ParseSchema` time.**Query allow-listing:** in production, consider persisted queries (gqlgen APQ extension) to reject arbitrary query strings.
查看另外 2 个位置
references/gqlgen.md:279来自说明文档打开原文件
srv.SetQueryCache(lru.New[*ast.QueryDocument](1000))if os.Getenv("ENV") != "production" {    srv.Use(extension.Introspection{})}srv.Use(extension.AutomaticPersistedQuery{Cache: lru.New[string](100)})srv.Use(extension.FixedComplexityLimit(200))```
SKILL.md:242来自说明文档打开原文件
**Query allow-listing:** in production, consider persisted queries (gqlgen APQ extension) to reject arbitrary query strings.
中风险

“生产配置”中的 WebSocket 省略了同文档展示的来源校验和连接认证

原文依据:2 处
发现了什么

订阅示例明确配置 `CheckOrigin` 和 `InitFunc` 验证 token,但后面的 Production Handler Setup 使用了裸 `transport.Websocket`,没有保留这两个控制,也没有在该片段中说明由外层中间件承担。

为什么需要注意

若用户把生产片段当作完整公开配置,且其他层没有实施等效控制,跨站连接尝试或未认证客户端可能到达订阅端点并保持长连接。

订阅章节展示了 WebSocket 来源限制和连接时令牌验证,但标为“Production Handler Setup”的片段随后仅启用裸 WebSocket transport,没有这些控制。若用户直接采用生产片段,跨来源连接和订阅认证可能缺失;普通 HTTP 中间件也未在该片段中说明能覆盖 WebSocket 初始化。用户可要求作者把 `CheckOrigin`、`InitFunc` 或明确等效的外层控制纳入完整生产示例。

references/gqlgen.md:199来自说明文档打开原文件
```gosrv.AddTransport(transport.Websocket{    KeepAlivePingInterval: 10 * time.Second,    Upgrader: websocket.Upgrader{        // Restrict to your own origin in production; true here is dev-only.        CheckOrigin: func(r *http.Request) bool {            return r.Header.Get("Origin") == "https://app.example.com"        },    },    InitFunc: func(ctx context.Context, initPayload transport.InitPayload) (context.Context, *transport.InitPayload, error) {        // auth at connection time        token := initPayload.Authorization()        user, err := validateToken(token)        if err != nil {            return ctx, nil, err        }        return context.WithValue(ctx, userKey, user), &initPayload, nil    },})
查看另外 1 个位置
references/gqlgen.md:269来自说明文档打开原文件
## Production Handler Setup```gosrv := handler.New(es)srv.AddTransport(transport.Options{})srv.AddTransport(transport.GET{})srv.AddTransport(transport.POST{})srv.AddTransport(transport.MultipartForm{MaxUploadSize: 10 << 20, MaxMemory: 5 << 20})srv.AddTransport(transport.Websocket{KeepAlivePingInterval: 10 * time.Second})
中风险

工具权限包含不受子命令或目标限制的 git 与 curl

原文依据:2 处
发现了什么

权限声明允许 `Bash(git:*)` 和 `Bash(curl:*)`,同时还允许读写文件、代理和 WebFetch。其 GraphQL 实现目的不需要所有 git 写操作或向任意目标发送 curl 请求。

为什么需要注意

如果 Skill 被不可信项目内容误导,或代理行为偏离任务,这些权限可用于改动分支或远端、删除未跟踪文件,或把项目数据发送到外部地址。该声明本身不证明这些操作已发生。

权限声明是生效范围而非示例:除项目读写外,它允许任意 `git` 子命令、任意 `curl` 参数、WebFetch 和 Agent。实现 Go GraphQL 确实可能需要部分网络与版本控制操作,但这里没有把 git 限制为只读,也没有限制 curl 的目标;被触发时可修改仓库历史、访问远端或发送可读取的数据。用户可在启用前移除不需要的权限,或要求作者限定具体只读子命令和可信网络目标。

SKILL.md:18来自说明文档打开原文件
    skill-library-version: "0.17.89"allowed-tools: Read Edit Write Glob Grep Bash(go:*) Bash(golangci-lint:*) Bash(git:*) Agent WebFetch mcp__context7__resolve-library-id mcp__context7__query-docs Bash(curl:*) Bash(godig:*) Bash(gopls:*) LSP mcp__gopls__*paths:
查看另外 1 个位置
SKILL.md:2来自说明文档打开原文件
---name: golang-graphqldescription: "Implements GraphQL APIs in Golang using gqlgen or graphql-go. Apply when building GraphQL servers, designing schemas, writing resolvers, handling subscriptions, or integrating GraphQL with existing Go HTTP services. Also apply when the codebase imports `github.com/99designs/gqlgen` or `github.com/graph-gophers/graphql-go`."user-invocable: false
会不会误导 AI 或隐藏内容?检查工作说明是否要求 AI 忽略你的指令、干扰检查结果,或夹带看不见的文字。未发现风险
会不会偷偷改推广链接或收款方?检查是否强制替换推广链接或收款对象,同时要求隐瞒更改。未发现风险

Skill 逻辑拆解

8 个说明模块

该 Skill 用于设计和实现 Go GraphQL 服务,涵盖 schema、resolver、DataLoader、认证、订阅、测试和生产配置;主体是指导文档与示例,没有随包提供的可执行脚本。

查看原文
SKILL.md:2来自说明文档打开原文件
---name: golang-graphqldescription: "Implements GraphQL APIs in Golang using gqlgen or graphql-go. Apply when building GraphQL servers, designing schemas, writing resolvers, handling subscriptions, or integrating GraphQL with existing Go HTTP services. Also apply when the codebase imports `github.com/99designs/gqlgen` or `github.com/graph-gophers/graphql-go`."user-invocable: false
SKILL.md:259来自说明文档打开原文件
## Deep Dives- **[gqlgen reference](./references/gqlgen.md)** — codegen workflow, `gqlgen.yml`, DataLoaders, Federation v2, directives- **[graphql-go reference](./references/graphql-go.md)** — reflection resolver model, type mapping, tracing- **[Testing](./references/testing.md)** — gqlgen client harness, gqltesting, httptest patterns

在构建和审查模式下,Skill 会要求启动代理扫描用户代码库中的 resolver 约定或安全问题,因此启用后可能把较大范围的项目代码交给额外的代理上下文处理。

查看原文
SKILL.md:25来自说明文档打开原文件
**Modes:**- **Build mode** — generating new schemas, resolvers, or server setup: follow the skill's sequential instructions; launch a background agent to grep for existing resolver patterns and naming conventions before generating new code.- **Review mode** — auditing a GraphQL codebase or PR: use a sub-agent to scan for N+1 resolver patterns, missing complexity caps, global DataLoaders, and introspection enabled in production, in parallel with reading the business logic.

文档包含多项明确的防护建议,包括每请求创建 DataLoader、限制查询复杂度、生产环境关闭 introspection,以及在订阅中处理连接取消。

查看原文
SKILL.md:111来自说明文档打开原文件
Each `User.posts` resolver fires a SQL query per user without batching — O(n) DB calls for n users. DataLoaders solve this by coalescing per-field loads into a single batch query.**Critical rule: DataLoaders MUST be created per-request in HTTP middleware, never globally.** A global DataLoader caches across requests — stale data, potential cross-user data leakage.
SKILL.md:225来自说明文档打开原文件
## Performance and SafetyProduction GraphQL servers require explicit limits. Without them, a single deeply nested query exhausts CPU and memory.```go// gqlgen — wire these into every production handlersrv := handler.NewDefaultServer(es)srv.Use(extension.FixedComplexityLimit(200)) // max cost per query// Gate introspection — only in non-production environmentsif os.Getenv("ENV") != "production" {    srv.Use(extension.Introspection{})}```
从这里开始 · 工作说明SKILL.md
golang-graphql
连线表示工作说明包含的模块,不是实际运行顺序。点击模块可查看原文。 另有 4 个章节,可在原文件中查看。

文件引用关系图

3 处引用
哪些文件发起引用引用了什么
连线表示真实的文件引用,不是运行顺序。点击节点可高亮相关连线,并查看具体文件和原文位置。虚线表示还有文件需要定位。
文件与检查记录5 个文件

检查范围与遗漏

逐文件查看涉及的内容

下方列出本次涉及的原文范围;纳入检查不代表已查清所有问题。

  • SKILL.md已纳入全文
  • references/gqlgen.md已纳入全文
  • references/graphql-go.md已纳入全文
  • references/testing.md已纳入全文
  • evals/evals.json已纳入全文

这份报告只针对上方版本。我们看了拿到的代码和说明文件,没有实际运行 Skill,也没有检查它另外安装的软件包。因此,这不是“保证安全”的承诺;换了版本或使用环境,结果也可能不同。

  • SKILL.md工作说明
  • evals/evals.json配套文件
  • references/gqlgen.md配套文件
  • references/graphql-go.md配套文件
  • references/testing.md配套文件

代码和说明中提到的操作

连接外部网站
SKILL.md:12来自说明文档打开原文件
    emoji: "🔮"    homepage: https://github.com/samber/cc-skills-golang    requires:
SKILL.md:18来自说明文档打开原文件
    skill-library-version: "0.17.89"allowed-tools: Read Edit Write Glob Grep Bash(go:*) Bash(golangci-lint:*) Bash(git:*) Agent WebFetch mcp__context7__resolve-library-id mcp__context7__query-docs Bash(curl:*) Bash(godig:*) Bash(gopls:*) LSP mcp__gopls__*paths:
SKILL.md:276来自说明文档打开原文件
- [gqlgen](https://github.com/99designs/gqlgen)- [graph-gophers/graphql-go](https://github.com/graph-gophers/graphql-go)
运行命令
SKILL.md:18来自说明文档打开原文件
    skill-library-version: "0.17.89"allowed-tools: Read Edit Write Glob Grep Bash(go:*) Bash(golangci-lint:*) Bash(git:*) Agent WebFetch mcp__context7__resolve-library-id mcp__context7__query-docs Bash(curl:*) Bash(godig:*) Bash(gopls:*) LSP mcp__gopls__*paths:
references/gqlgen.md:21来自说明文档打开原文件
```bash# Bootstrap a new project
references/gqlgen.md:31来自说明文档打开原文件
```bash# Regenerate after every schema change
读取密钥或账号配置
SKILL.md:235来自说明文档打开原文件
// Gate introspection — only in non-production environmentsif os.Getenv("ENV") != "production" {    srv.Use(extension.Introspection{})
references/gqlgen.md:280来自说明文档打开原文件
srv.SetQueryCache(lru.New[*ast.QueryDocument](1000))if os.Getenv("ENV") != "production" {    srv.Use(extension.Introspection{})
读取文件
references/gqlgen.md:240来自说明文档打开原文件
Resolver receives `graphql.Upload{File io.Reader, Filename string, Size int64, ContentType string}`.
读取了多少行
1,208
文件校验值(用于核对版本)
88deffa1081d12cae29bd07b5c47867b0d832a72298a0fb1763e8c044e5b21c7