feat(ssrf): implement SSRF protection for spec loading and external $ref resolution#7
Conversation
- Set package version to 2.4.0
WalkthroughAdds a new ChangesSSRF Hardening (GHSA-65h7-9wrw-629c)
Sequence Diagram(s)sequenceDiagram
participant Client
participant fromURL as OpenAPIToolGenerator.fromURL
participant safeFetch
participant assertUrlSafe
participant DNS as defaultLookup (DNS)
participant RemoteServer
Client->>fromURL: url, LoadOptions
fromURL->>safeFetch: url, ssrf + timeout opts
safeFetch->>assertUrlSafe: initial URL, ResolvedSsrfOptions
assertUrlSafe->>DNS: resolve hostname
DNS-->>assertUrlSafe: ResolvedAddress[]
assertUrlSafe-->>safeFetch: throws SsrfError (if blocked)
safeFetch->>RemoteServer: GET url (redirect: manual)
RemoteServer-->>safeFetch: 3xx Location header
safeFetch->>assertUrlSafe: redirect target URL
assertUrlSafe-->>safeFetch: throws SsrfError (if redirect blocked)
safeFetch->>RemoteServer: GET redirect target
RemoteServer-->>safeFetch: 200 OK + body
safeFetch-->>fromURL: Response
fromURL-->>Client: parsed OpenAPI spec / LoadError
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 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 |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
src/__tests__/generator.spec.ts (1)
204-210: 🧹 Nitpick | 🔵 Trivial | 💤 Low valueInconsistent error matchers across assertions.
Line 206 uses a regex
/blocked/iwhile lines 207-208 use theLoadErrorclass. SinceSsrfErrorextendsLoadError, both technically pass, but using consistent matchers improves test clarity about which error type is expected.♻️ Suggested fix for consistency
it('should refuse a spec URL pointing at a literal internal IP (SSRF guard)', async () => { // Literal internal IPs are rejected synchronously, before any fetch. - await expect(OpenAPIToolGenerator.fromURL('http://127.0.0.1:8080/openapi.json')).rejects.toThrow(/blocked/i); - await expect(OpenAPIToolGenerator.fromURL('http://169.254.169.254/openapi.json')).rejects.toThrow(LoadError); - await expect(OpenAPIToolGenerator.fromURL('http://[::1]/openapi.json')).rejects.toThrow(LoadError); + await expect(OpenAPIToolGenerator.fromURL('http://127.0.0.1:8080/openapi.json')).rejects.toThrow(SsrfError); + await expect(OpenAPIToolGenerator.fromURL('http://169.254.169.254/openapi.json')).rejects.toThrow(SsrfError); + await expect(OpenAPIToolGenerator.fromURL('http://[::1]/openapi.json')).rejects.toThrow(SsrfError); expect(mockFetch).not.toHaveBeenCalled(); });Add
SsrfErrorto the imports at the top of the file.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/__tests__/generator.spec.ts` around lines 204 - 210, The test method `should refuse a spec URL pointing at a literal internal IP (SSRF guard)` has inconsistent error matchers across its three assertions. Line 206 uses a regex pattern `/blocked/i` while lines 207-208 use the LoadError class matcher. To improve clarity and consistency, import SsrfError at the top of the file if not already present, and update all three expect statements to use SsrfError as the expected error type instead of mixing regex and class matchers.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@src/__tests__/generator.spec.ts`:
- Around line 204-210: The test method `should refuse a spec URL pointing at a
literal internal IP (SSRF guard)` has inconsistent error matchers across its
three assertions. Line 206 uses a regex pattern `/blocked/i` while lines 207-208
use the LoadError class matcher. To improve clarity and consistency, import
SsrfError at the top of the file if not already present, and update all three
expect statements to use SsrfError as the expected error type instead of mixing
regex and class matchers.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 9fa817b1-1736-463f-829b-af3e5c77600e
📒 Files selected for processing (9)
CHANGELOG.mdpackage.jsonsrc/__tests__/generator.spec.tssrc/__tests__/ssrf.spec.tssrc/errors.tssrc/generator.tssrc/index.tssrc/ssrf.tssrc/types.ts
Summary by CodeRabbit
Security
SsrfErrorexception type for security-related failures.New Features
Tests