Skip to content

fix(evm): remove unauthenticated NFT metadata endpoint (SSRF, FOX-168)#1280

Merged
kaladinlight merged 1 commit into
developfrom
fix/evm-metadata-url-validation
Jun 12, 2026
Merged

fix(evm): remove unauthenticated NFT metadata endpoint (SSRF, FOX-168)#1280
kaladinlight merged 1 commit into
developfrom
fix/evm-metadata-url-validation

Conversation

@0xApotheosis

@0xApotheosis 0xApotheosis commented Jun 12, 2026

Copy link
Copy Markdown
Member

Description

Removes GET /api/v1/metadata/token and all of its supporting code instead of trying to sandbox the outbound fetch.

The endpoint made an unauthenticated server-side HTTP request to a URL taken straight from attacker-controlled NFT metadata (on-chain tokenURI(), plus image / animation_url), and followed redirects with no host allowlist or private-IP filtering. That's a blind SSRF (HackenProof FOX-168) — the only signal reflected to the client is the fetched Content-Type mapped to image/video.

Since the endpoint is unused by the web app, deleting it eliminates the attack surface entirely rather than mitigating it with an outbound-URL allowlist (which stays exposed to DNS-rebinding / TOCTOU).

Changes

  • evm/controller.ts — remove the /metadata/token route handler.
  • evm/models.ts — remove TokenMetadata, TokenType, and getTokenMetadata from the API interface.
  • evm/moralisService.ts / evm/blockbookService.ts — remove the getTokenMetadata implementations and now-unused imports.

routes.ts / swagger.json are gitignored tsoa build artifacts and regenerate from the controller, so they don't need touching.

Severity note

Assessed Low: blind SSRF with a 1-bit content-type oracle, no response-body reflection, and no demonstrated credential path. These APIs run in Railway's isolated/containerized environment with no cloud IMDS reachable, so the usual SSRF → credential-theft escalation doesn't apply. Reported as High; removing the feature outright is the cleanest remediation regardless.

Breaking change

/api/v1/metadata/token is a public endpoint on api.<chain>.shapeshift.com. Any third-party consumer relying on it will 404 after this. Confirmed unused by the ShapeShift web app.

Verification

Didn't run build/tests locally per repo CLAUDE.md. Change is a pure deletion of a self-contained feature; remaining TokenMetadata/TokenType/getTokenMetadata references are zero across source.

Summary by CodeRabbit

  • Refactor
    • Removed token metadata retrieval capability across EVM blockchain APIs. The GET /api/v1/metadata/token endpoint, which previously returned metadata for ERC-721 and ERC-1155 tokens by contract address and token ID, is no longer available on Arbitrum, Avalanche, Base, BNB Smart Chain, Ethereum, Gnosis, Optimism, and Polygon.

@0xApotheosis 0xApotheosis requested a review from a team as a code owner June 12, 2026 05:17
@coderabbitai

coderabbitai Bot commented Jun 12, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 1fe9de9b-e082-4717-969f-a0cf41815c50

📥 Commits

Reviewing files that changed from the base of the PR and between 0930a21 and 401f544.

📒 Files selected for processing (12)
  • node/coinstacks/arbitrum/api/src/swagger.json
  • node/coinstacks/avalanche/api/src/swagger.json
  • node/coinstacks/base/api/src/swagger.json
  • node/coinstacks/bnbsmartchain/api/src/swagger.json
  • node/coinstacks/common/api/src/evm/blockbookService.ts
  • node/coinstacks/common/api/src/evm/controller.ts
  • node/coinstacks/common/api/src/evm/models.ts
  • node/coinstacks/common/api/src/evm/moralisService.ts
  • node/coinstacks/ethereum/api/src/swagger.json
  • node/coinstacks/gnosis/api/src/swagger.json
  • node/coinstacks/optimism/api/src/swagger.json
  • node/coinstacks/polygon/api/src/swagger.json
💤 Files with no reviewable changes (9)
  • node/coinstacks/optimism/api/src/swagger.json
  • node/coinstacks/common/api/src/evm/models.ts
  • node/coinstacks/avalanche/api/src/swagger.json
  • node/coinstacks/base/api/src/swagger.json
  • node/coinstacks/bnbsmartchain/api/src/swagger.json
  • node/coinstacks/polygon/api/src/swagger.json
  • node/coinstacks/arbitrum/api/src/swagger.json
  • node/coinstacks/ethereum/api/src/swagger.json
  • node/coinstacks/gnosis/api/src/swagger.json
🚧 Files skipped from review as they are similar to previous changes (2)
  • node/coinstacks/common/api/src/evm/controller.ts
  • node/coinstacks/common/api/src/evm/moralisService.ts

📝 Walkthrough

Walkthrough

This PR removes the token metadata feature from the EVM coinstack: types and API contract, controller route, service implementations (Blockbook/Moralis), and the per-chain OpenAPI token-metadata schemas and endpoint.

Changes

EVM Token Metadata Feature Removal

Layer / File(s) Summary
Remove token metadata types and API contract
node/coinstacks/common/api/src/evm/models.ts
The exported TokenType union and TokenMetadata interface are removed and getTokenMetadata(...) is removed from the exported API interface.
BlockbookService implementation and imports
node/coinstacks/common/api/src/evm/blockbookService.ts
getTokenMetadata method removed; viem and axios imports narrowed (drop getContract, ABI constants, and AxiosError), and models type imports drop metadata types.
MoralisService implementation and imports
node/coinstacks/common/api/src/evm/moralisService.ts
getTokenMetadata method removed; ./models imports reorganized to exclude TokenMetadata/TokenType.
Controller endpoint and imports
node/coinstacks/common/api/src/evm/controller.ts
GET /metadata/token handler and related decorators removed; controller ./models imports drop metadata types.
Per-chain OpenAPI specs
node/coinstacks/*/api/src/swagger.json (arbitrum, avalanche, base, bnbsmartchain, ethereum, gnosis, optimism, polygon)
Remove components.schemas.TokenMetadata and TokenType and the GET /api/v1/metadata/token path from each swagger.json.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 With a twitch of whiskers, code trimmed neat,

Tokens' portraits folded, gone from the sheet,
Types and routes hopped out of view,
Services now lean, the API too,
🥕 Hop, patch, ship — a tidy feat!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title clearly and specifically describes the main change: removing an unauthenticated NFT metadata endpoint due to a security vulnerability (SSRF), with ticket reference.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/evm-metadata-url-validation

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint install failed. For unrecoverable errors, disable the tool in CodeRabbit configuration.


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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@kaladinlight kaladinlight force-pushed the fix/evm-metadata-url-validation branch from 901afb5 to 0930a21 Compare June 12, 2026 23:26
@kaladinlight kaladinlight changed the title fix(evm): validate NFT media/metadata URLs before fetching fix(evm): remove unauthenticated NFT metadata endpoint (SSRF, FOX-168) Jun 12, 2026

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🤖 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.

Inline comments:
In `@node/coinstacks/common/api/src/evm/controller.ts`:
- Line 12: The checked-in OpenAPI contract still advertises the removed endpoint
/api/v1/metadata/token and the TokenMetadata schema; regenerate or prune the
swagger.json to remove the stale path and schema so docs/clients no longer
advertise a dead route. Specifically, run the swagger/OpenAPI generation used by
this project (or manually edit the spec) to delete the /api/v1/metadata/token
path and the TokenMetadata component, ensuring the updated contract matches the
actual controller surface (controller.ts imports/models) and commit the
regenerated swagger.json.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c453dc94-4f86-4f43-91ed-61b189ac28ca

📥 Commits

Reviewing files that changed from the base of the PR and between 515bc55 and 0930a21.

📒 Files selected for processing (4)
  • node/coinstacks/common/api/src/evm/blockbookService.ts
  • node/coinstacks/common/api/src/evm/controller.ts
  • node/coinstacks/common/api/src/evm/models.ts
  • node/coinstacks/common/api/src/evm/moralisService.ts
💤 Files with no reviewable changes (1)
  • node/coinstacks/common/api/src/evm/models.ts

Comment thread node/coinstacks/common/api/src/evm/controller.ts
Remove `GET /api/v1/metadata/token` and all of its supporting code
(controller route, TokenMetadata/TokenType models, and the moralis +
blockbook getTokenMetadata implementations).

The endpoint made unauthenticated server-side HTTP requests to URLs
derived from attacker-controlled NFT metadata (on-chain `tokenURI()`,
`image`, `animation_url`), following redirects with no host allowlist
or private-IP filtering. This is a blind SSRF (FOX-168) whose only
reflected signal is the fetched `Content-Type` (image/video).

The endpoint is unused by the web app, so removing the feature
eliminates the attack surface outright rather than mitigating it with
an outbound-URL allowlist (which remains exposed to DNS-rebinding).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@kaladinlight kaladinlight force-pushed the fix/evm-metadata-url-validation branch from 0930a21 to 401f544 Compare June 12, 2026 23:31
@kaladinlight kaladinlight merged commit 99d5dd4 into develop Jun 12, 2026
3 checks passed
@kaladinlight kaladinlight deleted the fix/evm-metadata-url-validation branch June 12, 2026 23:46
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.

2 participants