Skip to content

Survive recursive and hostile specs; add build_info/uptime metrics - #44

Merged
haasonsaas merged 1 commit into
mainfrom
fix/adversarial-hardening
Aug 4, 2026
Merged

Survive recursive and hostile specs; add build_info/uptime metrics#44
haasonsaas merged 1 commit into
mainfrom
fix/adversarial-hardening

Conversation

@haasonsaas

Copy link
Copy Markdown
Collaborator

Adversarial-input hardening, found by feeding the server deliberately hostile specs (closes the concrete part of #21, plus the telemetry ask in #22):

Recursive $refs crashed the server — any spec with a self-referencing schema (Node.child -> Node, common in real APIs) failed twice:

  1. lintOpenApiDocument's broken-ref walker recursed the cyclic dereferenced document until Maximum call stack size exceeded — startup fatal.
  2. Even past lint, the compile cache's JSON.stringify threw on cyclic operation models.

Fixes: the lint walker tracks visited nodes; the schema normalizer cuts cycle back-references to the permissive empty schema so compiled models are serializable and AJV/Zod-compilable; cache writes are best-effort (warn and continue); the openapi://<name>/spec resource renders back-references as "[Circular]".

__proto__ schema properties were silently unvalidated — building Zod shapes via computed assignment on a plain object hits the prototype setter, so a property literally named __proto__ was dropped from validation. Shapes and normalized schema nodes now use null-prototype objects; such properties validate like any other, and the tests assert Object.prototype stays clean.

Telemetry: /metrics gains mcp_openapi_build_info{version="…"} 1 and mcp_openapi_uptime_seconds.

Tests: 6 new (58 total) — cyclic-spec compile/serialize/validate, full --validate-spec startup on a cyclic spec, cyclic spec resource read over stdio, __proto__ validation + no-pollution assertions, duplicate-operationId suffixing, metrics rendering.

🤖 Generated with Claude Code

https://claude.ai/code/session_01LqBsGC7xLvihtBxhCdWKz5

Recursive $refs (self-referencing schemas, common in real APIs) crashed
the server two ways: the lint walker recursed the cyclic dereferenced
document until stack overflow, and the compile cache JSON.stringify
threw on cyclic operation models. The linter now tracks visited nodes,
the schema normalizer cuts cycles to the permissive empty schema so
compiled models are serializable and AJV/Zod-compilable, the cache
write is best-effort, and the spec resource renders back-references as
"[Circular]".

Schema property names like __proto__ were silently dropped from Zod
shapes (computed assignment hits the prototype setter); shapes and
normalized schema nodes now use null-prototype objects so such
properties are validated like any other.

/metrics gains mcp_openapi_build_info{version} and
mcp_openapi_uptime_seconds.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LqBsGC7xLvihtBxhCdWKz5
@haasonsaas
haasonsaas merged commit d013ce6 into main Aug 4, 2026
4 checks passed
@haasonsaas
haasonsaas deleted the fix/adversarial-hardening branch August 4, 2026 09:15
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