Repository navigation
pin kagent 0.1.22: the per-user tool path leaked the user's JWT on a failed call - #829
Merged
Merged
Conversation
…failed call Security priority. On a failed kubectl call the per-user tool path returned the user's JWT in the tool result (kagent-dev/tools#107). All 98 stored tokens were already expired; its owner redacts the session store separately. The per-user tool server now comes from a PRIVATE krateo-agentiko package pinned BY DIGEST ONLY, ghcr.io/krateo-agentiko/kagent-tools@sha256:6308035d...230c, under the new key perUserRbac.toolImage. There is no tag field at all, so no stale tag can win over the digest -- the trap that defeated the ClickHouse digest pin. repository and digest are deliberately NOT set in componentValues: the chart default IS the pin, and a second source would re-create that hazard. inst.privateImageComponents gains {name: kagent, path: [perUserRbac, toolImagePullSecrets]} so the existing registryAuth-derived dockerconfigjson pulls the private image with no manual ServiceAccount patch. 057 already has it: krateo-registry-image-pull, covering host ghcr.io, which is the same host as the new package, and inst.imagePullAuths dedupes one auths entry per host. 0.1.21 IS DELIBERATELY SKIPPED, and the reason is the point of this commit. 0.1.21 carried the pull secret INSIDE toolImage, whose schema requires [repository, digest]. crdgen preserves chart `required` into the composition CRD -- verified with krateo-audit-worm as a control, whose 5 chart-level blocks appear verbatim as .spec.* required in both its served versions -- and the image-pull injection CREATES each parent object while setting only the leaf. So the installer would have written toolImage: {pullSecrets: [...]} with neither required sibling, and the apiserver would have REJECTED the Kagent CR outright on any cluster with registryAuth enabled, which includes 057. Its owner moved the key to the sibling toolImagePullSecrets in 0.1.22 so the injection never touches toolImage. The injected shape was checked against 0.1.22's own schema before pinning: {enabled: true, toolImagePullSecrets: [{name: krateo-registry-image-pull}]} has no unknown keys, satisfies the item's required [name], and does not construct toolImage. perUserRbac itself carries no `required`, and the chart has no root `required`, so nothing here can wedge the umbrella. No componentValues widening is needed: the injection writes onto the composition spec AFTER the componentValues merge, so it is validated by the component's own crdgen CRD and never passes through the installer's componentValues schema. Asserted: 85 other pins byte-identical; the privateImageComponents list parses to exactly 8 entries with every pre-existing path unchanged. The first attempt at that edit matched a PREFIX of the agentgateway-policies uiTokenHop entry and spliced the new block in front of its `- image`/`- pullSecrets` lines, orphaning them onto kagent; caught by parsing the rendered YAML rather than trusting the diff, and re-anchored on the following entry. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016RAxvmbdtWAFW9j2vWsv7a
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Security priority. On a failed kubectl call the per-user tool path returned the user's JWT in the tool result ([kagent-dev/tools#107]). All 98 stored tokens were already expired; its owner redacts the session store separately.
What changes
kagent0.1.20 → 0.1.22. The per-user tool server now comes from a private krateo-agentiko package pinned by digest only —ghcr.io/krateo-agentiko/kagent-tools@sha256:6308035d…230c— under the new keyperUserRbac.toolImage. There is no tag field at all, so no stale tag can win over the digest, which is the trap that defeated the ClickHouse digest pin.inst.privateImageComponentsgains{name: kagent, path: [perUserRbac, toolImagePullSecrets]}, so the existingregistryAuth-derived dockerconfigjson pulls the private image with no manual ServiceAccount patch.repositoryanddigestare deliberately not set incomponentValues: the chart default is the pin, and a second source would recreate the stale-value hazard this design removes.Why 0.1.21 is skipped — the point of this commit
0.1.21 carried the pull secret inside
toolImage, whose schema requires[repository, digest]. crdgen preserves chartrequiredinto the composition CRD — verified withkrateo-audit-wormas a control, whose 5 chart-level blocks appear verbatim as.spec.*required in both served versions — and the image-pull injection creates each parent object while setting only the leaf:So the installer would have written
toolImage: {pullSecrets: [...]}with neither required sibling, and the apiserver would have rejected theKagentCR outright on any cluster withregistryAuthenabled — which includes 057. Its owner moved the key to the siblingtoolImagePullSecretsin 0.1.22 so the injection never touchestoolImage.Checked before pinning
{enabled: true, toolImagePullSecrets: [{name: krateo-registry-image-pull}]}— no unknown keys, satisfies itemrequired: [name], does not constructtoolImagerequired/perUserRbacrequiredkrateo-registry-image-pullalready covers hostghcr.io, the same host as the new package;inst.imagePullAuthsdedupes oneauthsentry per host9.9.9absent as negative)privateImageComponentsOne mistake worth recording: the first attempt at the helper edit matched a prefix of the
agentgateway-policiesuiTokenHopentry and spliced the new block in front of its- image/- pullSecretslines, orphaning them ontokagentand corrupting both entries. Caught by parsing the rendered YAML rather than trusting the diff, then re-anchored on the following entry.🤖 Generated with Claude Code
https://claude.ai/code/session_016RAxvmbdtWAFW9j2vWsv7a