[security-audit-agent] Security Audit Findings — 2026-06-15#102
Conversation
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: rosa-regional-platform-ci The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
|
Warning Review limit reached
More reviews will be available in 58 minutes and 8 seconds. Learn how PR review limits work. Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file). ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Repository: openshift-online/coderabbit/.coderabbit.yaml Review profile: CHILL Plan: Enterprise Run ID: 📒 Files selected for processing (1)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Hi @rosa-regional-platform-ci. Thanks for your PR. I'm waiting for a openshift-online member to verify that this patch is reasonable to test. If it is, they should reply with Tip We noticed you've done this a few times! Consider joining the org to skip this step and gain Once the patch is verified, the new status will be reflected by the I understand the commands that are listed here. DetailsInstructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. |
Security Audit — rosa-regional-platform-api
Date: 2026-06-15
Auditor: Automated security-audit-agent
Method: Full static analysis of Go source files, Kubernetes manifests, Envoy configuration, CI scripts, Dockerfiles
Action required: Triage each finding below. This PR does not contain fixes — it exists to track and communicate security issues for owner review.
CRITICAL Findings
CRIT-1 — Authentication via Forgeable HTTP Headers (carry-over from #85/#97, unresolved)
File:
pkg/middleware/identity.goRisk: The entire authentication model trusts
X-Amz-Account-Id,X-Amz-Caller-Arn, and related HTTP headers with no cryptographic verification. Any caller that bypasses Envoy and reaches the API pod directly can forge any identity, including privileged accounts.Attack vectors:
X-Amz-Account-Id: <target>andX-Amz-Caller-Arn: arn:aws:iam::<target>:role/OrganizationAccountAccessRole— impersonates any account.Mitigation: Validate requests using an HMAC or shared secret injected only by Envoy/API Gateway. Remove port 8000 from the Kubernetes Service. Enforce NetworkPolicy restricting ingress to port 8000 to localhost only.
CRIT-2 — Kubernetes Service Exposes Raw API Port 8000, Bypassing Envoy Sidecar (NEW)
File:
deployment/manifests/api.yamlRisk: Port 8000 is the raw application port, bypassing the Envoy sidecar that sets identity headers. Any pod in the cluster can call
http://rosa-regional-platform:8000and reach the application with no identity context. The identity middleware receives requests with emptyX-Amz-*headers, and behavior with missing headers may allow unauthenticated operations.Attack vector: Compromised pod calls port 8000 directly — no identity headers, no Envoy middleware, direct application access.
Mitigation: Remove ports 8000, 8081, and 9090 from the Kubernetes Service. Add NetworkPolicy denying all ingress except port 8080 from ALB/monitoring sources.
HIGH Findings
HIGH-1 — Authorization Silently Disabled When Config Is Missing (carry-over from #85/#97, unresolved)
File:
pkg/server/server.goRisk: When
cfg.Authzis nil or disabled, the server falls back to account-allowlist-only mode with no per-resource authorization. Any misconfiguration (missing env var, DynamoDB connection failure) silently degrades security. Any allowlisted account gets full access to all operations.Mitigation: Fail-closed: if authz is expected but config is missing/invalid, exit with a fatal error rather than starting in degraded mode.
HIGH-2 — No Request Body Size Limits Enable Memory Exhaustion DoS (carry-over from #97, unresolved)
Files:
pkg/handlers/cluster.go:85,pkg/handlers/nodepool.go:81, and 40+ handler locationsRisk: All handlers use
json.NewDecoder(r.Body).Decode()withouthttp.MaxBytesReader. A client sends a largeContent-Length, causing the pod to OOM. Any authorized account can trigger this — no auth bypass needed.Mitigation: Add middleware:
r.Body = http.MaxBytesReader(w, r.Body, 10*1024*1024)HIGH-3 — Hardcoded Privileged Test Account in e2e Script (carry-over from #97, unresolved)
File:
scripts/e2e-init-dynamodb.shRisk: If
$ENDPOINTis empty or misconfigured, account000000000000is written as privileged in production DynamoDB. This account ID is public in source code.Mitigation: Abort if
$ENDPOINTis notlocalhost/127.0.0.1. Use a randomly generated test account ID.HIGH-4 — Authorization Middleware Fails Open on DynamoDB Errors (carry-over from #97, unresolved)
Files:
pkg/middleware/account_check.go,pkg/middleware/privileged.goRisk: When DynamoDB is unavailable, both middleware functions log an error and allow the request to proceed with unverified authorization state. This is fail-open.
Mitigation: Return
503 Service Unavailablewhen the authorization backend is unreachable.HIGH-5 — Unpinned Container Images in Deployment Manifest (NEW)
File:
deployment/manifests/api.yamlRisk:
cdoan0's account updates the production API (withimagePullPolicy: Always).Mitigation: Move the API image to
quay.io/rrp-dev-ci/or theopenshift-onlineorg. Pin both images to SHA256 digests.HIGH-6 — Prometheus Metrics Exposed Cluster-Wide Without Authentication (carry-over from #85, partially mitigated)
File:
deployment/manifests/api.yaml,pkg/server/server.goRisk: Metrics endpoint on
0.0.0.0:9090is exposed via the Kubernetes Service on port 9090 with no authentication. Any cluster pod can scrape operational intelligence about the API service.Mitigation: Bind to
127.0.0.1or add bearer token auth. Remove port 9090 from the Kubernetes Service. Add NetworkPolicy restricting scraping to the Prometheus namespace.MEDIUM Findings
MED-1 — Wildcard CORS Policy (carry-over from #85, unresolved)
File:
pkg/server/server.go—handlers.AllowedOrigins([]string{"*"})Mitigation: Restrict to specific frontend domains.
MED-2 — Identity Headers Not Validated for Format (carry-over from #85, unresolved)
File:
pkg/middleware/identity.goRisk:
X-Amz-Account-Idaccepts arbitrary strings. AWS account IDs are always 12-digit numbers. Malformed values enable log injection and downstream key injection.Mitigation: Validate against
/^\d{12}$/. Return400 Bad Requestfor malformed values.MED-3 — Build Stage Dockerfile Uses Unpinned
golang:1.25-alpine(NEW)File:
Dockerfileline 2 —FROM golang:1.25-alpine AS builderMitigation: Pin to SHA256 digest.
MED-4 — Runtime Dockerfile Uses Unpinned
distroless/static-debian12:nonroot(NEW)File:
Dockerfile—FROM gcr.io/distroless/static-debian12:nonrootMitigation: Pin to SHA256 digest.
Full findings detail is in
SECURITY-AUDIT.mdadded in this PR.