Skip to content

V1.1 tier b#23

Merged
mikeappsec merged 3 commits into
mainfrom
v1.1-tier-b
May 1, 2026
Merged

V1.1 tier b#23
mikeappsec merged 3 commits into
mainfrom
v1.1-tier-b

Conversation

@mikeappsec

Copy link
Copy Markdown
Owner

No description provided.

dev added 3 commits April 30, 2026 23:58
F13 (Medium): Multi-value credential-header order-dependence. JSON body
  {x-api-key:[bogus,valid]} is well-formed, never trips the F6
  dup-key walker or F9 case-collision check, but Request.Header() returns
  vs[0] only -- so the verdict flips between 200 and 401 purely on slice
  order. Front layers (Envoy, nginx, CDNs) fold duplicate header lines
  inconsistently => parser-differential. lowercaseHeaderKeys now rejects
  len > 1 with 400 so credential identifiers see exactly one value.

F14 (Medium): gRPC connection-management defaults missing.
  buildGRPCServerOptions now wires
    KeepaliveEnforcementPolicy{MinTime:30s, PermitWithoutStream:false}
    KeepaliveParams{MaxConnectionIdle:5m, MaxConnectionAge:30m,
                    Grace:30s, Time:1m, Timeout:20s}
    MaxConcurrentStreams:1024
  All knobs operator-tunable via Options.GRPCKeepalive* /
  Options.GRPCMaxConnection* / Options.GRPCMaxConcurrentStreams.
  Without these a malicious client can park thousands of idle TCP/HTTP-2
  connections to exhaust FDs and goroutines (each accepted gRPC conn
  spawns a server reader goroutine via transport.http2Server).

F15 (Info): host / tenantId structural validation. validateAuthorizeShape
  refuses CRLF in host (regex ^[A-Za-z0-9._-]+(:[0-9]{1,5})?$) and bounds
  tenantId at 256 bytes printable ASCII. No in-tree module reflects
  these values into a response header today, but the surface is one
  config knob away (e.g. an OAuth2 module deriving WWW-Authenticate
  realm from host).

Regression tests:
- TestHTTPHandler_RejectsMultiValueHeader (F13): two-, three-, and
  mixed canonical+multi cases plus a single-value negative control
- TestHTTPHandler_RejectsStructuralJunkInHostAndTenant (F15): CRLF/LF/
  whitespace/tab in host, NUL/newline/oversize in tenantId, 5 negatives
- TestBuildGRPCServerOptions_F14_KeepaliveAndStreamsWired (F14):
  default / explicit-knobs / body-cap-disabled configurations all
  produce the expected option count and survive grpc.NewServer.

All go test ./... green.
Fix the mkdocs --strict build failure on CI (10 warnings -> error).

- nav: add 'OAuth2 Authorization Code + PKCE: cookbook/oauth2-pkce.md'
  so the new recipe is no longer orphaned.
- exclude_docs: add 'internal/**' alongside the existing PENTEST_REPORT_*
  pattern. docs/internal/ is engagement-time scratch (dry-run issue
  lists, draft GitHub issues) that intentionally cross-references
  source-tree files via repo-relative '../../foo/bar.go' paths.
  Those links are correct on GitHub but cannot satisfy mkdocs strict
  link checking, which resolves them inside docs/. Published
  cross-references continue to use absolute https://github.com/...
  URLs as already documented in the validation block.

Verified: 'python -m mkdocs build --strict' completes with no warnings.
5 findings identified and closed:

1. idp.yaml: Pod-level securityContext missing (runAsNonRoot, runAsUser
   65532, seccompProfile:RuntimeDefault). A container default could
   run as root. Fixed: added podSecurityContext to spec.template.spec.

2. backend.yaml: no securityContext at all. Fixed: full restricted
   profile (runAsNonRoot, readOnlyRootFilesystem, drop ALL).

3. backend.yaml: no network-layer isolation. The cookbook claimed
   'only requests carrying a valid JWT reach this Pod' but that was
   only true at the HTTP layer via ext_authz; at the network layer
   anything could reach httpbin directly. Fixed: added NetworkPolicy
   (backend-allow-gateway-only) restricting ingress to only the
   gateway Pod (matchLabels app.kubernetes.io/component:gateway).

4. gateway.yaml template: no stream_idle_timeout / request_timeout
   on the Envoy HttpConnectionManager. A malicious client could hold
   connections open indefinitely. Fixed: stream_idle_timeout=300s,
   request_timeout=60s.

5. run_flow.py: static state='xyz123' set a bad CSRF example. Fixed:
   state is now secrets.token_urlsafe(16) per run; the script asserts
   the returned state matches (round-trip check).

Docs: updated cookbook 'What this exercises' table to reflect the
random-state + NetworkPolicy additions.

All go test ./... green (including helm render tests).
@mikeappsec
mikeappsec merged commit b088682 into main May 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant