Skip to content

feat: close 4 more audit findings (SEC-005, SDK-002, OBS-006, SCALE-002/003)#11

Merged
malkreide merged 3 commits into
mainfrom
claude/cool-rubin-0gH4z
Jun 1, 2026
Merged

feat: close 4 more audit findings (SEC-005, SDK-002, OBS-006, SCALE-002/003)#11
malkreide merged 3 commits into
mainfrom
claude/cool-rubin-0gH4z

Conversation

@malkreide

@malkreide malkreide commented Jun 1, 2026

Copy link
Copy Markdown
Owner

Closes every remaining audit finding that is fixable without a product/scope change. Re-audit: 39 pass / 5 partial / 0 fail (from 37/7/0; high findings 3→2, medium 4→2).

What changed

Finding Sev Before → After Change
SEC-005 high partial → pass DNS-pinned transport (_PinnedNetworkBackend via httpcore): host resolved exactly once, IP validated + pinned for the TCP connection, TLS SNI/cert still verified against the hostname (kills the resolve/connect TOCTOU). Verified end-to-end against a real host.
SDK-002 medium partial → pass Typed structured output: all 6 tools declare Pydantic output schemas and return a hybrid CallToolResult with both the curated Markdown/JSON (content) and a validated structuredContent envelope — machine-readable, no UX loss.
OBS-006 medium partial → pass OpenTelemetry on by default (MCP_OTEL_ENABLED=0 to disable); silent no-op when the [otel] extra is absent, so base installs and stdout (OBS-004) are unaffected. Verified TracerProvider + OTLP + span creation.
SCALE-002/003 high partial (improved) deploy/haproxy.cfg — reference sticky-session config (Mcp-Session-Id stick-table + TTL) for the horizontal-scaling path.

Verification

  • ✅ 57 unit tests pass (egress split, DNS-pinning, structured-content, otel toggle), ruff clean, wheel builds.
  • ✅ Live test: pinned GET to www.fedlex.admin.ch resolves once, dials the pinned IP, TLS validates against the hostname.
  • ✅ Structured output smoke-tested for all 6 tools (schema built, structuredContent validated, Markdown preserved).
  • ✅ OTel wiring verified with the [otel] extra installed; clean stdout on import.
  • Merged latest main (dependabot bumps) — conflict resolved.

Remaining (5) — each a deliberate decision, not a bug

  • SEC-009 (critical) — would require authentication (changes the public no-auth design). Accepted-risk.
  • SCALE-002/003 (high) — full pass needs an actual multi-instance + failover test; config provided.
  • SEC-014 / SEC-015 (medium) — require an enterprise MCP gateway. Accepted-risk.

These stand as documented accepted-risk / deferred. The v0.2.0 release is ready whenever you want it.

https://claude.ai/code/session_01CokY47qCb5iHuAfAEWdCvU

malkreide added 3 commits June 1, 2026 04:39
Closes the last code-fixable HIGH finding and provides the scaling artifact.

- SEC-005 (high, partial->pass): DNS-pinned HTTP transport
  (_PinnedNetworkBackend via httpcore network_backend). Host is resolved
  exactly once, the resolved IP is validated against the SSRF blocklist and
  the TCP connection is pinned to it, while TLS SNI + certificate verification
  still use the original hostname (eliminates the resolve/connect TOCTOU).
  Verified end-to-end against a real host (live test).
- SCALE-002/003: deploy/haproxy.cfg reference sticky-session config
  (Mcp-Session-Id stick-table + explicit session TTL) for the horizontal-
  scaling path; documented in docs/SECURITY.md.

Egress guard split: _assert_safe_url (scheme + host allow-list, no DNS) +
_resolve_and_validate (single resolution + IP blocklist + pinned IP).

Re-audit record: pass 36->37, partial 8->7, 0 fail. 56 unit tests (+4),
ruff clean, wheel builds.

https://claude.ai/code/session_01CokY47qCb5iHuAfAEWdCvU
…(OBS-006)

SDK-002 (medium, partial->pass): all 6 tools now declare typed Pydantic
output schemas and return a hybrid CallToolResult carrying BOTH the curated
Markdown/JSON in content AND a validated structuredContent envelope. Machine
consumers get a real output schema with no loss of the human-readable UX.
New models: BaseEnvelope, SLSucheEnvelope/SLTreffer, GGSLEnvelope,
MiGeLEnvelope, GesuchseingaengeEnvelope, RechtskontextEnvelope/Gesetz,
ServerInfoEnvelope; helper _structured_result().

OBS-006 (medium, partial->pass): MCP_OTEL_ENABLED now defaults on; _init_otel
is a silent no-op when the [otel] extra is absent, so base installs and stdout
(OBS-004) are unaffected. Verified TracerProvider + OTLP + span creation with
the extra installed.

Tests updated to read content/structuredContent (helpers _text/_struct);
added otel-toggle + structured-content assertions. 57 unit tests, ruff clean,
wheel builds. Re-audit: pass 37->39, partial 7->5, 0 fail.

https://claude.ai/code/session_01CokY47qCb5iHuAfAEWdCvU
@malkreide malkreide changed the title feat: DNS-pinning (SEC-005) + sticky-session config (SCALE-002/003) feat: close 4 more audit findings (SEC-005, SDK-002, OBS-006, SCALE-002/003) Jun 1, 2026
@malkreide malkreide marked this pull request as ready for review June 1, 2026 16:07
@malkreide malkreide merged commit e7149e6 into main Jun 1, 2026
3 checks passed
@malkreide malkreide deleted the claude/cool-rubin-0gH4z branch June 1, 2026 16:07
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