Skip to content

API requests only go to the API host - #56

Merged
paynejd merged 6 commits into
masterfrom
OpenConceptLab/ocl_online#554-api-host-only
Oct 21, 2026
Merged

paynejd merged 6 commits into
masterfrom
OpenConceptLab/ocl_online#554-api-host-only

Conversation

@paynejd

@paynejd paynejd commented Oct 21, 2026

Copy link
Copy Markdown
Member

Summary

Hardening: API requests only go to the API host.

  • overrideURL accepts a path starting with exactly one /, or an absolute URL on the API's own origin. Anything else is refused.
  • sendRequest and request send 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.
  • Token-less requests (headers 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.js with 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

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
@paynejd

paynejd commented Oct 21, 2026

Copy link
Copy Markdown
Member Author

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 baseURL before comparing origins. Both are being fixed in this PR.

…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
@paynejd

paynejd commented Oct 21, 2026

Copy link
Copy Markdown
Member Author

Review, pass 2 (Codex, commit eda542e): three minor findings. Some header layouts aren't seen by the check, and the previous commit dropped a baseURL path prefix and a relative API_URL's subdirectory. The next commit moves the check to the point where axios has its final URL and headers, and stops rewriting the URL.

…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
@paynejd

paynejd commented Oct 21, 2026

Copy link
Copy Markdown
Member Author

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
@paynejd

paynejd commented Oct 21, 2026

Copy link
Copy Markdown
Member Author

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.

paynejd and others added 2 commits October 21, 2026 13:48
…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
@paynejd

paynejd commented Oct 21, 2026

Copy link
Copy Markdown
Member Author

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.

@paynejd
paynejd requested review from snyaggarwal and removed request for snyaggarwal October 21, 2026 20:46
@paynejd
paynejd merged commit 98383af into master Oct 21, 2026
6 checks passed
@paynejd
paynejd deleted the OpenConceptLab/ocl_online#554-api-host-only branch October 21, 2026 21:09
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