F01 | CONFIRMED | src/controller/artifact/processor/base/manifest.go:99 | `json.NewDecoder(blob).Decode(v)` decodes the whole attacker-supplied config blob into map[string]interface{} with no io.LimitReader; only `mani.Config.Size == 0` is checked (line 88), and the path is reached on every manifest PUT (src/server/registry/manifest.go:128 artifact.Ctl.Ensure -> controller.go:205 abstractor -> abstractor.go:83).
F04 | CONFIRMED | src/server/v2.0/handler/icon.go:38 | GetIcon calls `i.ctl.Get(ctx, params.Digest)` with no RequireAuthenticated/RequireProjectAccess (contrast robot.go:168), and the swagger declares anonymous access globally (api/v2.0/swagger.yaml:18-20 `security: - basic: [] - {}`); impact is limited to resized icon images, consistent with Low.
F07 | CONFIRMED | src/server/middleware/repoproxy/proxy.go:170 | `setHeaders(w, ..., art.Digest)` and setHeaders (proxy.go:198-199) unconditionally set Docker-Content-Digest/Etag; for a tag reference artifactinfo.Middleware sets only `art.Tag` and leaves Digest empty (artifact_info.go:128-132), so both headers are emitted as empty strings.
F10 | CONFIRMED | src/server/middleware/immutable/pushmf.go:50-52 | `if err != nil { log.Debugf(...); return nil }` allows the push on ANY error from artifact.Ctl.GetByReference, not just NotFound, so the immutable-tag check fails open (CWE-636).
F13 | CONFIRMED | src/server/v2.0/handler/notification_policy.go:116,129-130 | `lib.JSONCopy(policy, params.Policy)` copies the body's `id` (swagger.yaml:7909 `id` is a writable property; model.go:16 `json:"id"`), the path param WebhookPolicyID is never used, ProjectID is force-set to the URL project, and dao.Update (dao.go:89 `ormer.Update(policy)`) writes by primary key — so a foreign policy can be updated and re-parented.
F16 | CONFIRMED | src/server/handler/job_status_hook.go:37-45 | ServeHTTP decodes the body and calls `j.handler.Handle` with no security-context or secret check; the global chain only populates a context (security.Middleware) and falls back to an unauthorized one (security.go:69-73), and route.go:53-59 registers the endpoints with no auth wrapper. External reachability depends on the front proxy config, which is not in this tree.
F19 | CONFIRMED | src/controller/artifact/processor/chart/chart.go:87 | `ioutil.ReadAll(blob)` reads the whole non-config layer into memory with no size bound; reachable with only ActionRead on ResourceArtifactAddition (src/server/v2.0/handler/artifact.go:431) and recomputed per request (controller.go:559-564 GetAddition has no cache).
F22 | CONFIRMED | src/server/v2.0/handler/preheat.go:645-650 | Authorization is ActionUpdate on ResourcePreatPolicy in params.ProjectName, then `api.executionCtl.Stop(ctx, params.ExecutionID)` runs with no check that the execution belongs to that project or is a preheat execution — execution_controller.go:57 and pkg/task/execution.go:249 stop by raw ID across all vendor types (GC, replication, retention, scan-all).
F25 | CONFIRMED | src/server/middleware/csrf/csrf.go:57 | `log.Warningf("Invalid CSRF key from environment: %s, ...", key)` writes the operator-supplied CSRF_KEY verbatim to the log; the claim overstates it slightly — this branch runs only when len(key) != 32, so the key actually in use (a valid 32-byte one) is never logged.
F28 | CONFIRMED | src/server/v2.0/handler/retention.go:344-353 | Access is checked against the policy identified by params.ID, then the log is fetched with `GetRetentionExecTaskLog(ctx, params.Tid)` — controller.go:363-365 is a bare `taskMgr.GetLog(ctx, taskID)` with no check that the task belongs to that policy's executions.
F31 | CONFIRMED | src/server/v2.0/handler/robot.go:287 | `rAPI.requireAccess(ctx, params.Robot.Level, params.Robot.Permissions[0].Namespace, ActionUpdate)` authorizes against the body-supplied namespace, while the robot itself was loaded by ID at robot.go:191; only level and name are compared to the stored robot (line 291). GetRobotByID (line 179) shows the correct pattern using `r.ProjectID`.
F34 | CONFIRMED | src/server/middleware/csrf/csrf.go:56-58 | The `len(key) != 32` branch logs the env-supplied key and then replaces it with `utils.GenerateRandomString()` — exactly as the claim describes: secret material reaches the log (CWE-532) but is not the key in use.
F37 | CONFIRMED | src/controller/artifact/processor/chart/chart.go:92 | `p.chartOperator.GetDetails(content)` -> src/pkg/chart/operator.go:91 `loader.LoadArchive(reader)` -> vendored helm src/vendor/helm.sh/helm/v3/pkg/chart/loader/archive.go:105,172 `gzip.NewReader` + `io.Copy(b, tr)` into an unbounded bytes.Buffer, with no decompressed-size cap.
F40 | CONFIRMED | src/server/v2.0/handler/preheat.go:721-725 | Access is checked on params.ProjectName, then `api.taskCtl.GetLog(ctx, params.TaskID)` runs unscoped — src/controller/task/controller.go:76-78 is a bare `mgr.GetLog(ctx, id)` with no execution/project/vendor binding.
F43 | CONFIRMED | src/server/v2.0/handler/notification_job.go:30-43 | ActionList is checked on the URL project, then `webhookPolicyMgr.Get(ctx, params.PolicyID)` fetches any policy and the query is keyed on `policy.ID` with no comparison of `policy.ProjectID` to the authorized project.
F46 | CONFIRMED | src/server/middleware/util/util.go:70-71 | `secCtx.Can(..., ActionPush, ...) && strings.Contains(r.UserAgent(), "cosign")` returns skip=true, and SkipPolicyChecking gates all three enforcement middlewares (contenttrust/notary.go:56, contenttrust/cosign.go:41, vulnerable/vulnerable.go:71). Precondition the claim omits: a "v2token" security context with push rights on that repository — not any anonymous attacker.
F49 | CONFIRMED | src/server/v2.0/handler/retention.go:197-210 | `p` (including Scope) comes from the request body, `p.ID` from the path, then `requireAccess` authorizes on `p.Scope.Reference` (line 366) while `UpdateRetention` writes by `p.ID` (src/controller/retention/controller.go:126-127) — authorize on body scope, write by path ID.
F52 | CONFIRMED | src/controller/proxy/controller.go:229 | `artInfo.Digest = dig` uses the digest returned by remote.Manifest, which is the upstream's Docker-Content-Digest header taken verbatim with no sha256(payload) check (src/pkg/registry/client.go:288-290), and that digest keys the redis manifest-list cache (manifestcache.go:70-76) and the artifact record. Severity is bounded as the claim itself states (needs a hostile upstream/MITM; clients verify digests themselves).
F55 | CONFIRMED | src/controller/artifact/processor/chart/chart.go:87-91 | The error path `content, err := ioutil.ReadAll(blob); if err != nil { return nil, err }` returns before `blob.Close()` at line 91, leaking the registry response body. The claimed attacker-driven trigger is not supported by this tree: registry.client.PullBlob builds its request with `http.NewRequest` and no request context (client.go:350), so a client abort/stall cannot cancel the core->registry read.
F58 | CONFIRMED | src/server/v2.0/handler/preheat.go:258-267 | ActionUpdate is checked on params.ProjectName, then `convertParamPolicyToModelPolicy` carries the body's `ID` and `ProjectID` (preheat.go:469,472) straight into `preheatCtl.UpdatePolicy`, which loads and updates by `schema.ID` (src/controller/p2p/preheat/controller.go:334) with no project cross-check; the path param PreheatPolicyName is ignored (contrast CreatePolicy at line 245, which overrides ProjectID).
