Skip to content

security: reject foreign-host URLs in api to prevent token leak#478

Merged
jeremy merged 1 commit into
mainfrom
security/01-api-token-leak
Jul 14, 2026
Merged

security: reject foreign-host URLs in api to prevent token leak#478
jeremy merged 1 commit into
mainfrom
security/01-api-token-leak

Conversation

@jeremy

@jeremy jeremy commented May 30, 2026

Copy link
Copy Markdown
Member

Reject foreign-host URLs in api to prevent bearer-token leak

Severity: High — credential exfiltration primitive. (Threat: T1 malicious/compromised API target.)

parsePath only extracted the path from absolute URLs whose first segment was a numeric account ID. Any other absolute URL (e.g. https://evil.example/projects.json) failed the regex, fell through the no-op TrimPrefix, and was returned verbatim to app.Account().Get/Post/Put/Delete — the SDK then attached the Authorization: Bearer header and sent the request to the foreign host.

Fix

parsePath now returns (string, error) and accepts an absolute http(s):// URL only when its host matches the API base host we're authenticated against (case-insensitive). URLs on any other host are rejected before any request is made, so the OAuth token can never be sent to a foreign host. Same-host URLs are used as given: the path (plus query) is passed through with no account-segment shape requirement — a leading /<account-id> segment, if present, is dropped since the SDK re-prefixes the configured account. Error propagated through all four api handlers.

Tests

api_test.go adds a table for relative / leading-slash / valid-account / foreign-host inputs (TestParsePathRejectsForeignHosts). Legitimate https://3.basecampapi.com/999/... still extracts correctly.


Part 1/6 of a stacked security-hardening series (audit remediation). This one is independent and safe to land alone; the rest stack on top in order. Base: main.

📚 Stack (merge bottom-up)

  1. security: reject foreign-host URLs in api to prevent token leak #478 — reject foreign-host URLs in api (base main)
  2. security: strip ANSI/OSC escapes from API-controlled output #479 — strip ANSI/OSC escapes from output
  3. security: harden OAuth discovery and token endpoints #480 — harden OAuth discovery / token endpoints
  4. security: close config trust-boundary gaps and gate completion loader #481 — close config trust-boundary gaps + completion gate
  5. security: tighten config-dir perms and validate plugin scope argv #482 — tighten config-dir perms + plugin scope argv
  6. security: pin the gitleaks download with a SHA-256 checksum #483 — bump toolchain/x-net + CI gates

Each is independent except #482 depends on #481 (shared root.go). #478 can land first/alone.

Copilot AI review requested due to automatic review settings May 30, 2026 05:58
@github-actions github-actions Bot added commands CLI command implementations tests Tests (unit and e2e) labels May 30, 2026
@github-actions github-actions Bot added the breaking Breaking change label May 30, 2026
@github-actions

github-actions Bot commented May 30, 2026

Copy link
Copy Markdown

⚠️ Potential breaking changes detected:

  • The function parsePath was modified to reject absolute URLs pointing to foreign hosts. URLs that were previously accepted by parsePath, even if they were on foreign hosts, will now cause an error, which can change the behavior of the CLI and break existing scripts.

Review carefully before merging. Consider a major version bump.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Hardens the basecamp api subcommand against a credential-exfiltration vector. Previously, parsePath silently passed any non-canonical absolute URL through to the SDK, which would then attach the user's Authorization: Bearer header and send it to the foreign host. parsePath now returns an error for absolute http(s):// URLs that aren't of the form https://<host>/<numeric-account-id>/..., and all four api verb handlers propagate that error before any network call.

Changes:

  • Change parsePath signature from (string) to (string, error) and reject absolute URLs that don't match the canonical Basecamp account-id form.
  • Wire error propagation through the get/post/put/delete RunE handlers.
  • Add TestParsePathRejectsForeignHosts and update TestParsePath for the new return signature.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
internal/commands/api.go parsePath now returns an error and rejects non-canonical absolute URLs; all four handlers propagate the error.
internal/commands/api_test.go Updates existing test to new signature; adds table-driven test asserting rejection of foreign/non-canonical URLs.

Tip

If you aren't ready for review, convert to a draft PR.
Click "Convert to draft" or run gh pr ready --undo.
Click "Ready for review" or run gh pr ready to reengage.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread internal/commands/api.go Outdated
@jeremy jeremy force-pushed the security/01-api-token-leak branch from b6d427d to 2eacce7 Compare May 30, 2026 06:05
@github-actions github-actions Bot removed the breaking Breaking change label May 30, 2026

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 2 files

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread internal/commands/api.go Outdated
Comment thread internal/commands/api.go Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2eacce7710

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread internal/commands/api.go Outdated
@jeremy jeremy force-pushed the security/01-api-token-leak branch from 2eacce7 to 447cbf3 Compare May 30, 2026 06:23
Copilot AI review requested due to automatic review settings May 30, 2026 06:23

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

@jeremy jeremy force-pushed the security/01-api-token-leak branch from 447cbf3 to 2734359 Compare May 30, 2026 07:51
Copilot AI review requested due to automatic review settings July 2, 2026 18:38
@robzolkos robzolkos force-pushed the security/01-api-token-leak branch from 2734359 to 396f100 Compare July 2, 2026 18:38
@github-actions github-actions Bot added the breaking Breaking change label Jul 2, 2026

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

Comment thread internal/commands/api_test.go
@robzolkos robzolkos force-pushed the security/01-api-token-leak branch from 396f100 to 20854f7 Compare July 2, 2026 19:00
@github-actions github-actions Bot added the bug Something isn't working label Jul 2, 2026
Copilot AI review requested due to automatic review settings July 13, 2026 22:57
@jeremy jeremy force-pushed the security/01-api-token-leak branch from 20854f7 to d932099 Compare July 13, 2026 22:57

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

Comment thread internal/commands/api.go
Comment thread internal/commands/api_test.go Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d932099ec2

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread internal/commands/api.go Outdated
Copilot AI review requested due to automatic review settings July 13, 2026 23:23
@jeremy jeremy force-pushed the security/01-api-token-leak branch from d932099 to dfb4c74 Compare July 13, 2026 23:23
@github-actions github-actions Bot removed the breaking Breaking change label Jul 13, 2026

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

Comment thread internal/commands/api.go
Comment thread internal/commands/api_test.go
Copilot AI review requested due to automatic review settings July 13, 2026 23:48
@jeremy jeremy force-pushed the security/01-api-token-leak branch from dfb4c74 to fc7bafa Compare July 13, 2026 23:48

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

Copilot AI review requested due to automatic review settings July 14, 2026 05:19
@jeremy jeremy force-pushed the security/01-api-token-leak branch from fc7bafa to e56fa0c Compare July 14, 2026 05:19

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

Comment thread internal/commands/api.go
Copilot AI review requested due to automatic review settings July 14, 2026 06:08
@jeremy jeremy force-pushed the security/01-api-token-leak branch from e56fa0c to a97718e Compare July 14, 2026 06:08

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

Comment thread internal/commands/api.go
parsePath now validates absolute URLs against the configured base URL host:
a path is accepted only if it's relative or an absolute Basecamp URL on the
same host (path extracted, account segment dropped — the SDK re-prefixes the
configured account). Absolute URLs on any other host are rejected before any
network call, so the SDK never attaches the Authorization: Bearer header to a
foreign host. A stray leading slash ('/https://evil/…') and mixed-case schemes
('HTTPS://…') are normalized first so neither can smuggle an absolute URL past
the host check. Error propagated through get/post/put/delete; api_test.go
covers same-host extraction, query preservation, and foreign-host rejection.
Copilot AI review requested due to automatic review settings July 14, 2026 06:43
@jeremy jeremy force-pushed the security/01-api-token-leak branch from a97718e to 10057f5 Compare July 14, 2026 06:43

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

@jeremy jeremy merged commit eecc121 into main Jul 14, 2026
26 checks passed
@jeremy jeremy deleted the security/01-api-token-leak branch July 14, 2026 19:42
@jeremy jeremy restored the security/01-api-token-leak branch July 14, 2026 19:43
@jeremy jeremy deleted the security/01-api-token-leak branch July 14, 2026 19:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working commands CLI command implementations tests Tests (unit and e2e)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants