security: fix beta9 P0 findings (auth fails-open, unauth control API, SSRF, plaintext creds, gateway panic) - #4
Merged
Wingie merged 2 commits intoJul 19, 2026
Conversation
… SSRF, plaintext creds, gateway panic) Applies the P0 security hardening from the FlowState audit (wip-specs/beta9/2026-07-13-p0-security-fixes.md). Built against fork HEAD 84ea11c; cross-compiles clean for linux/amd64. 1. Inference API auth was fails-open — AuthMiddleware only populated the auth context, it never rejected anonymous callers, so /chat/completions, /embeddings, /models, /nodes/register, /nodes/:id/heartbeat ran regardless of auth. Node/model management now requires TokenTypeClusterAdmin; chat/embeddings/listing require any authenticated token. 2. SSRF via unvalidated tailscale_ip — handleRegisterNode and MachineKeepalive stored a caller-supplied IP verbatim and used it to build outbound requests. Both now reject anything outside the allowed private range. 3. Unauthenticated agent control API — pkg/agent/control.go endpoints hardened. 4. Plaintext credentials in manifests/k3d/beta9.yaml — removed. 5. Gateway panic path fixed. Files: manifests/k3d/beta9.yaml, pkg/agent/control.go, pkg/api/v1/machine.go, pkg/api/v1/workspace.go, pkg/gateway/inference_handlers.go Co-Authored-By: Claudistrator <savetheplanet@agentosaurus.com>
…via CI gate) The lint_and_test_python_sdk check on PR #4 flagged ruff F401 (unused ChatMessage/EmbeddingResult imports in test_cubic_fixes.py). Rather than just delete the imports, running the suite behind that gate surfaced a real bug: - inference.embed() overloaded the singular `embedding` field with the whole batch list and never populated the plural `embeddings` field, so callers of result.embeddings got an empty list for batch input. test_batch_embeddings was already failing (0 != 3) — hidden because the lint step failed first. Fixes: - embed() now sets `embedding` = first vector (legacy accessor) and `embeddings` = the full batch, per EmbeddingResult's documented field intent. - test_batch_embeddings now asserts the return type (uses EmbeddingResult). - Added test_chat_forwards_chatmessage covering the previously-untested ChatMessage -> dict conversion in chat() (uses ChatMessage). Full SDK suite: 63 passed; ruff clean. Co-Authored-By: Claudistrator <savetheplanet@agentosaurus.com>
Wingie
merged commit Jul 19, 2026
95618d0
into
claude/agentic-rag-browser-use-deps
2 of 3 checks passed
Wingie
added a commit
that referenced
this pull request
Aug 3, 2026
- Add GPUType field to InferenceStatus in keepalive payload - Add InferenceGPUType to AgentState and AgentStateSnapshot - Add UpdateInferenceWithGPU() method; UpdateInference() stays for compat - StartInference() reads gpu_type from OllamaManager.GetStatus() after start - Gateway keepalive handler uses reported GPUType instead of hardcoded "MPS" - Falls back to "MPS" for old agents that omit the field (zero-value compat) Fixes the TODO at pkg/api/v1/machine.go:289. Rebased onto origin/main (689961d, PR #3 cubic-review-findings) — the prior branch tip was stacked on unmerged PR #4 (security fixes) which had since diverged from main, producing conflicts. Re-resolved cleanly: kept main's current locally-scoped NodeInferenceInfo type in machine.go (main never migrated it to types.NodeInferenceInfo, unlike what the original fvks-branch commit assumed) and layered the gpuType variable/fallback on top of it. BD: FlowState-fvks Co-Authored-By: Claudistrator <savetheplanet@agentosaurus.com>
Wingie
added a commit
that referenced
this pull request
Aug 3, 2026
Both branches independently fixed the same two bugs; kept the stronger side of each and dropped the now-redundant duplicate: - pkg/agent/control.go: two overlapping model-name validators (isValidOllamaModelName from this branch, isAllowedModelName from origin/main PR #3). Kept isValidOllamaModelName — it's a superset (also rejects fully-qualified registry paths, not just shell metacharacters/traversal) — and removed the now-unused duplicate. Existing TestInferencePullRejectsInvalidModelName payloads (shell metachars, path traversal, empty) are all still rejected. - sdk/src/beta9/inference.py: two fixes for the same embed() batch- routing bug. Kept this branch's simpler always-populate-both-fields version (matches the EmbeddingResult dataclass's own docstring: embedding="Legacy: First embedding if batch", embeddings="New: All embeddings") over origin/main's is_batch-conditional version, which zeroes out .embedding for batches of 2+ results — an untested edge case that contradicts the documented contract. test_cubic_fixes.py's test_batch_embeddings only asserts .embeddings for the batch case, so both variants passed it; picked by contract match, not by the test. This merge exists so the P0 security fixes here (InferenceRegistry signature fix — see the added comment in pkg/api/v1/machine.go history — auth fails-open, unauth control API, SSRF, plaintext creds, gateway panic) don't get silently dropped from the beta9-infra submodule pin by rebasing straight onto origin/main, which was the first (wrong) approach tried for PR #5's GPU-type-propagation conflict.
Wingie
added a commit
that referenced
this pull request
Aug 3, 2026
- Add GPUType field to InferenceStatus in keepalive payload - Add InferenceGPUType to AgentState and AgentStateSnapshot - Add UpdateInferenceWithGPU() method; UpdateInference() stays for compat - StartInference() reads gpu_type from OllamaManager.GetStatus() after start - Gateway keepalive handler uses reported GPUType instead of hardcoded "MPS" - Falls back to "MPS" for old agents that omit the field (zero-value compat) Fixes the TODO at pkg/api/v1/machine.go:289. Applied on top of the merge of origin/main into PR #4 (95618d0) rather than directly on origin/main, so this branch keeps PR #4's InferenceRegistry signature fix — main's info := &NodeInferenceInfo{} (locally-scoped, plain type) doesn't satisfy InferenceRegistry.RegisterNode(*types.NodeInferenceInfo), so main still carries the P0 panic-on-startup bug PR #4 fixed. Uses types.NodeInferenceInfo here to match. BD: FlowState-fvks Co-Authored-By: Claudistrator <savetheplanet@agentosaurus.com>
3 tasks
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.
What
Lands the P0 security hardening that was audited + patch-prepared in FlowState (
wip-specs/beta9/2026-07-13-p0-security-fixes.md) but couldn't be pushed from that session (no beta9 push access). Applied on top of the pinned base84ea11c1; cross-compiles clean forlinux/amd64(the deploy target).Fixes (5 P0s)
AuthMiddlewareonly populated the auth context; it never rejected anonymous callers, so/chat/completions,/embeddings,/models,/nodes/register,/nodes/:id/heartbeatserved regardless of auth state. Node/model management now requiresTokenTypeClusterAdmin; chat/embeddings/listing require any authenticated token.tailscale_ip—handleRegisterNode/MachineKeepalivestored a caller-supplied IP verbatim and used it to build outbound chat/embed requests. Both now reject anything outside the allowed private range.pkg/agent/control.go) — hardened.manifests/k3d/beta9.yaml— removed.Files
manifests/k3d/beta9.yaml,pkg/agent/control.go,pkg/api/v1/machine.go,pkg/api/v1/workspace.go,pkg/gateway/inference_handlers.goVerification
GOOS=linux GOARCH=amd64 go build ./...passes. Full unit tests run on Linux (this branch was prepared/verified on darwin, where the gateway/worker CRIU path can't compile — a separate cross-platform item).Follow-ups (tracked separately, not in this PR)
beam-cloud/beta9) sync.pkg/typesfrom the Linux-onlycedanadep).