Repository navigation
API requests only go to the API host - #56
Conversation
Hardening: APIService.overrideURL accepts only a path starting with a single "/" or an absolute URL on the API's own origin. Requests that carry the user's token are sent only to the API origin; anything else is refused with a rejected promise (no network call is made). Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VVCCrTucXFfAwXL8jNgbYB
|
Review, pass 1 (Codex, commit a8bee31): two minor findings. The token-origin check should match the Authorization header in any letter case, and it should resolve a request's axios |
…n header, resolve baseURL Hardening: detect the token case-insensitively in the headers axios will send (defaults and request), and validate the absolute URL axios would use, sending that URL with no baseURL. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VVCCrTucXFfAwXL8jNgbYB
|
Review, pass 2 (Codex, commit eda542e): three minor findings. Some header layouts aren't seen by the check, and the previous commit dropped a |
…n axios's final URL and headers Hardening: APIService requests use a guarded adapter that checks the merged headers and the final URL axios builds, instead of re-deriving them. Requests carrying the token are sent only to the API origin. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VVCCrTucXFfAwXL8jNgbYB
|
Review, pass 3 (Codex, commit fad9cf5): clean. The earlier findings are resolved. The check now runs where axios has its final URL and headers. A simplification pass and a final adversarial check follow. |
…er (simplify pass) Hardening cleanup: the adapter guard reuses the shared origin helper, the adapter is set in getRequest, and an unused export and constant are removed. Behaviour is unchanged. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VVCCrTucXFfAwXL8jNgbYB
|
Simplification pass and check (commit 57bdcc2): four small cuts were applied, and a Codex check of them came back clean. A final adversarial check follows. |
…wn config keys; refuse paths that resolve to // Hardening: request() passes on only a fixed set of config keys, and overrideURL refuses values with whitespace or control characters or whose path resolves to a double slash. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VVCCrTucXFfAwXL8jNgbYB
…control characters Hardening: overrideURL no longer refuses spaces, which cannot change the destination. It still refuses control characters and values whose path resolves to a double slash. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VVCCrTucXFfAwXL8jNgbYB
|
Review loop complete (head 0f337ef). Codex passes 1–3 and the follow-up checks are clean, and the adversarial check's in-scope items are fixed. The final fix restores concept paths that contain spaces. Ready to merge. |
Summary
Hardening: API requests only go to the API host.
overrideURLaccepts a path starting with exactly one/, or an absolute URL on the API's own origin. Anything else is refused.sendRequestandrequestsend a token-bearing request only if the final URL's origin equals the API origin. A refusal returns a rejected promise (Refused a request outside the OCL API), never a synchronous throw, and no axios call is made.false, as the FHIR operations drawer uses for external FHIR servers) are unaffected.Testing
The repo has no unit tests. I ran a throwaway Node script (not committed) against the transpiled
APIService.jswith a mocked axios. It covered: relative path sent; absolute same-origin sent; other-host absolute, no leading slash,//prefix, backslash and undefined all refused with no axios call; token-less external request still sent; token to an external URL blocked. Lint:eslint --ext .jsx,.js src/(the PR check's command) is clean.Related: OpenConceptLab/ocl_online#554
🤖 Generated with Claude Code
https://claude.ai/code/session_01VVCCrTucXFfAwXL8jNgbYB