Skip to content

Potential fix for code scanning alert no. 43: Server-side request forgery#985

Open
aaspinwall wants to merge 2 commits into
mainfrom
alert-autofix-43
Open

Potential fix for code scanning alert no. 43: Server-side request forgery#985
aaspinwall wants to merge 2 commits into
mainfrom
alert-autofix-43

Conversation

@aaspinwall

Copy link
Copy Markdown
Collaborator

Potential fix for https://github.com/thunderbird/tbpro-add-on/security/code-scanning/43

The best fix is to normalize and validate API paths before building the URL, and to construct URLs via new URL() + pathname joining rather than raw string concatenation.

Concretely in packages/send/frontend/src/lib/api.ts:

  1. Add a private sanitizer method on ApiConnection that:

    • rejects empty paths,
    • rejects absolute URLs / protocol-relative strings (http://, https://, //),
    • strips leading slashes,
    • splits by / and validates each segment with a conservative allowlist (e.g. alphanumerics, _, -, .),
    • URL-encodes each segment and rejoins with /.
  2. In call(...), replace

    • const url = \${this.serverUrl}/api/${path}`;`
    • const refreshTokenUrl = \${this.serverUrl}/api/auth/refresh`;with URL-construction usingnew URL()` and the sanitized path:
    • const safePath = this.normalizeApiPath(path);
    • const url = new URL(/api/${safePath}, this.serverUrl).toString();
    • const refreshTokenUrl = new URL('/api/auth/refresh', this.serverUrl).toString();

This preserves existing functionality for valid paths like uploads/${id}/stat while preventing malicious path content from steering requests to unintended endpoints.

Suggested fixes powered by Copilot Autofix. Review carefully before merging.

aaspinwall and others added 2 commits July 9, 2026 18:05
…gery

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
…typecheck

The Copilot autofix broke the build and runtime:
- `normalizeApiPath` was a private method on ApiConnection, which is used
  structurally as a mock type across stores/tests; a private member breaks that
  structural compatibility, failing `tsc` (frontend-tests-and-lint).
- Its per-segment allowlist rejected query strings (`.../links?type=file`),
  trailing slashes (`sharing/${hash}/`) and email path params
  (`users/lookup/${email}/`), and percent-encoded segments — breaking real
  endpoints (end-to-end tests).

Replace it with a module-level `buildApiUrl(serverUrl, path)` that rejects empty
and absolute/protocol-relative paths, strips leading slashes, resolves against
the server origin via `new URL('/api/' + path, serverUrl)`, and asserts the
resulting origin equals the configured origin before use. This closes the SSRF
vector (the host can never be steered by `path`) while preserving every existing
path unchanged. Adds unit tests for the guard and for `call()`'s URL building.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@aaspinwall
aaspinwall marked this pull request as ready for review July 10, 2026 17:33
@aaspinwall
aaspinwall requested a review from radishmouse July 10, 2026 17:34
@aaspinwall

Copy link
Copy Markdown
Collaborator Author

This is ready for review but low priority

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