oapi-codegen generates Go code from an OpenAPI specification. A malicious specification can inject arbitrary top-level Go (e.g. a func init()) into the generated types package by abusing a whole-document external $ref (a $ref whose target has no # fragment, e.g. ./evil.json). The injected code executes whenever the generated package is built or imported on the developer's or CI machine.
ValidateSpec (the sole spec gate — kin-openapi's own Validate() is never called) deliberately stops its walk at every $ref: walkSchemaRef early-returns whenever ref.Ref != "", on the documented assumption that "the contents of external documents are never copied into the generated output." For a whole-document reference this assumption is false:
IsGoTypeReference("./evil.json") = ref != "" && !IsWholeDocumentReference(ref) = true && !true = false (no # fragment, utils.go).GenerateGoSchema does NOT take the type-reference early-return (schema.go), and instead inlines the external object as a Go struct, emitting each external property name verbatim into a backtick-delimited struct tag (GenFieldsFromProperties, fmt.Sprintf(\%s:"%s"`, ...)then wrapped in backticks). The external subtree is therefore never routed throughcheckText`, which would otherwise reject backticks and newlines.Arbitrary Go code injection at build time (CWE-94). An attacker who controls an OpenAPI spec (or an external document it references) injects top-level declarations / func init() into the generated code, achieving code execution on the build/CI host. Same trust boundary and impact class as the project's existing enum/path/field code-injection advisories.
api.yaml declares components.schemas.Container.properties.evil: { $ref: ./evil.json }. Run oapi-codegen -generate types api.yaml (default flags, local file).ValidateSpec(spec) (codegen.go) -> walkSchema(Container) -> walkSchemaRef(evil).evil.SchemaRef.Ref == "./evil.json" (non-empty), so walkSchemaRef early-returns on ref.Ref != "" (validate_spec.go) BEFORE walkSchema(ref.Value) — the external property names are never seen by checkText. Empirically: loaded doc shows evil.Ref="./evil.json" with .Value != nil.GenerateGoSchema(ctx, evil, ...) (schema.go).if IsGoTypeReference(sref.Ref) early-return to a Go type name.IsGoTypeReference("./evil.json") = false (./evil.json has no #; confirmed by kin-openapi's own utils_test.go). Generation falls through to inline struct emission using sref.Value.GenFieldsFromProperties sets JsonFieldName: pName verbatim, feeds it through text/template (no escaping), assembles tags[i] = fmt.Sprintf(\%s:"%s"`, k, fieldTags[k])` and wraps the whole field in backticks." in the name does NOT break out — the true breakout char is a backtick (closes the raw string), after which a newline + func init(){...} becomes top-level Go.checkText would reject both, but it never ran on this subtree (step 1). Post-gen imports.Process is a formatter, not a sanitizer; SkipFmt/format-error return the raw goCode anyway.func init(), extra top-level decls) injected into the generated types package; executes when the package is built/imported.api.yaml: components.schemas.Container.properties.evil: {$ref: ./evil.json}
evil.json: object with a property name containing a backtick, a newline, and `func init(){}`
-> LOAD OK
-> evil.Ref="./evil.json" resolved(.Value!=nil)=true
-> external property name contains backtick=true newline=trueThe backtick+newline-bearing name reaches the struct-tag sink unescaped because checkText is skipped by the $ref early-return.
# evil.json (local file next to api.yaml)
{"type":"object","properties":{
"a` json:\"a\"`\nfunc init(){exec.Command(\"touch\",\"/tmp/PWNED\").Run()}\ntype _x struct{ A string `json:\"a":
{"type":"string"}}}
# api.yaml
components: {schemas: {Container: {type: object, properties: {evil: {$ref: ./evil.json}}}}}
# Container must be referenced by a path/response, or run with skip-prune.
oapi-codegen -generate types -o gen.go api.yaml # default flags
# gen.go now contains an injected top-level func init(){...}; `go build ./...` runs it.Up to and including v2.8.1 (verified present on the v2.8.1 release tag). Default configuration; no flag required for a local-file whole-document ref. A remote whole-document ref ($ref: https://host/evil.json) additionally requires --allow-remote-refs-from.
walkSchemaRef encounters a whole-document reference (ref with no # fragment) whose .Value is populated and will be inlined, do NOT early-return — recurse into ref.Value so checkText validates the inlined property names. Alternatively, run checkText on every property name actually emitted into a struct tag, regardless of its source document.Reported by zx (Jace) — GitHub: @manus-use
소스: NVD
무료 취약점 평가
9개 보안 영역에서 클라우드 보안 관행을 평가하여 위험 수준을 벤치마킹하고 방어의 허점을 파악하세요.
맞춤형 데모를 받아보세요
"내가 본 최고의 사용자 경험은 클라우드 워크로드에 대한 완전한 가시성을 제공합니다."
"Wiz는 클라우드 환경에서 무슨 일이 일어나고 있는지 볼 수 있는 단일 창을 제공합니다."
"우리는 Wiz가 무언가를 중요한 것으로 식별하면 실제로 중요하다는 것을 알고 있습니다."