Skip to content

🔒 Fix fallback of allowedOrigin to localhost in production#381

Open
is0692vs wants to merge 3 commits into
mainfrom
jules-9766932802489647517-7e5e2205
Open

🔒 Fix fallback of allowedOrigin to localhost in production#381
is0692vs wants to merge 3 commits into
mainfrom
jules-9766932802489647517-7e5e2205

Conversation

@is0692vs

@is0692vs is0692vs commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

🎯 What: The vulnerability fixed
In src/app/api/card/[username]/route.ts, if the APP_URL environment variable is not explicitly set, the allowedOrigin falls back to http://localhost:3000.

⚠️ Risk: The potential impact if left unfixed
This insecure fallback might cause fonts or other internal fetch requests to hit a local developer endpoint instead of the intended service in production environments. Crucially, this variable is used via renderCardResponse as the trusted allowedOrigin in isTrustedFontUrl (in validators.ts), potentially meaning that the production environment would implicitly trust localhost:3000 URLs when it shouldn't.

🛡️ Solution: How the fix addresses the vulnerability
The code now properly verifies the presence of the APP_URL environment variable. If APP_URL is empty and the environment is production, the server now explicitly returns a 500 Server configuration error. In non-production environments, it safely falls back to http://localhost:3000.


PR created automatically by Jules for task 9766932802489647517 started by @is0692vs

Greptile Summary

本PRは、APP_URL 環境変数が未設定の場合にproduction環境で http://localhost:3000 にフォールバックしてしまうセキュリティ上の問題を修正しています。修正後は、production環境かつ APP_URL が未設定の場合に renderErrorCardResponse を通じて500エラーを返し、非production環境では引き続き localhost:3000 へのフォールバックを維持します。

  • route.ts: allowedOrigin の決定ロジックを変更し、production環境での安全なエラーハンドリングを追加。エラーメッセージは汎用的な "Server configuration error" を使用しており、内部の環境変数名は露出しない設計になっています。
  • route.test.ts: APP_URL が未設定かつ NODE_ENV=production の場合に renderErrorCardResponse が正しく呼ばれることを検証する新しいテストケースを追加。

Confidence Score: 5/5

本番環境での誤ったlocalhostフォールバックを防ぐ小規模な修正で、安全にマージできます。

変更範囲はごく小さく、本番環境での誤ったフォールバックを正確に防いでいます。エラーメッセージは汎用的で内部情報を露出しておらず、レスポンス形式も統一されています。テストが新しいコードパスを網羅しており、既存の動作への影響もありません。

特に注意が必要なファイルはありません。

Important Files Changed

Filename Overview
src/app/api/card/[username]/route.ts allowedOriginの決定ロジックを改善。production環境でAPP_URLが未設定の場合、renderErrorCardResponseで500を返す安全なガードを追加。エラーレスポンス形式も他のエラーパスと統一されている。
src/app/api/card/[username]/route.test.ts 新しいAPP_URL検証テストを追加。vi.resetModules()をテストボディ内で呼び出す実装で、finallyブロックでvi.unstubAllEnvs()のみ復元しており、後続テストへの影響に注意が必要。

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[GET /api/card/:username] --> B{APP_URL is set?}
    B -- "Yes" --> C[allowedOrigin = APP_URL]
    B -- "No" --> D{NODE_ENV === 'production'?}
    D -- "Yes" --> E[renderErrorCardResponse\nstatus: 500\n'Server configuration error']
    D -- "No" --> F[allowedOrigin = 'http://localhost:3000']
    C --> G[fontUrl = allowedOrigin + /fonts/...]
    F --> G
    G --> H{Rate limit exceeded?}
    H -- "Yes" --> I[renderErrorCardResponse 429]
    H -- "No" --> J[fetchCardData]
    J -- "null" --> K[renderErrorCardResponse 404]
    J -- "data" --> L[renderCardResponse 200]
    J -- "error" --> M[renderErrorCardResponse 503]
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A[GET /api/card/:username] --> B{APP_URL is set?}
    B -- "Yes" --> C[allowedOrigin = APP_URL]
    B -- "No" --> D{NODE_ENV === 'production'?}
    D -- "Yes" --> E[renderErrorCardResponse\nstatus: 500\n'Server configuration error']
    D -- "No" --> F[allowedOrigin = 'http://localhost:3000']
    C --> G[fontUrl = allowedOrigin + /fonts/...]
    F --> G
    G --> H{Rate limit exceeded?}
    H -- "Yes" --> I[renderErrorCardResponse 429]
    H -- "No" --> J[fetchCardData]
    J -- "null" --> K[renderErrorCardResponse 404]
    J -- "data" --> L[renderCardResponse 200]
    J -- "error" --> M[renderErrorCardResponse 503]
Loading

Reviews (2): Last reviewed commit: "Fix APP_URL environment variable fallbac..." | Re-trigger Greptile

Co-authored-by: is0692vs <135803462+is0692vs@users.noreply.github.com>
@google-labs-jules

Copy link
Copy Markdown
Contributor

👋 Jules, reporting for duty! I'm here to lend a hand with this pull request.

When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down.

I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job!

For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

@vercel

vercel Bot commented Jun 12, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
github-user-summary Ignored Ignored Jul 8, 2026 6:34am

@qodo-code-review

Copy link
Copy Markdown

Qodo reviews are paused for this user.

Troubleshooting steps vary by plan Learn more →

On a Teams plan?
Reviews resume once this user has a paid seat and their Git account is linked in Qodo.
Link Git account →

Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center?
These require an Enterprise plan - Contact us
Contact us →

@dosubot dosubot Bot added the bug Something isn't working label Jun 12, 2026
@coderabbitai

coderabbitai Bot commented Jun 12, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Summary by CodeRabbit

  • Bug Fixes
    • APP_URL が未設定の場合の挙動を改善しました。
    • 本番環境では設定不足時にエラーを返して処理を停止し、開発環境ではローカルURLへフォールバックするようになりました。
    • これにより、誤った設定で不完全なレスポンスが返るリスクが減りました。

Walkthrough

GETハンドラ内でallowedOriginの決定方法を変更した。APP_URL環境変数が未設定の場合、NODE_ENVがproductionであれば500エラーで処理を中断し、それ以外の環境ではlocalhost URLにフォールバックするよう分岐処理を追加した。

Changes

allowedOrigin決定ロジックの修正

Layer / File(s) Summary
環境依存のallowedOriginフォールバック
src/app/api/card/[username]/route.ts
APP_URL未設定時にNODE_ENVをチェックし、production環境では500レスポンスで早期終了、それ以外ではhttp://localhost:3000にフォールバックする分岐ロジックを追加。

Estimated code review effort: 1 (Trivial) | ~5 minutes

Poem

APP_URLが見当たらぬなら
うさぎはピョンと確認するよ 🐰
本番ならば潔く止まり
それ以外はローカルへ跳ねる
小さな分岐、大きな安心

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed タイトルはproductionでのallowedOriginのlocalhostフォールバック修正という主要変更を簡潔に表しています。
Description check ✅ Passed 説明はAPP_URL未設定時のproduction向けガードと非productionでのlocalhostフォールバック維持を正しく述べています。
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.
✨ 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 jules-9766932802489647517-7e5e2205

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: one or more packages not found in the registry.


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.

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request improves environment variable validation in the card API route by returning a 500 error in production if the APP_URL environment variable is not configured. The reviewer suggested trimming APP_URL to prevent issues with accidental leading or trailing whitespace.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

const url = new URL(request.url);
const options = parseCardQueryParams(url.searchParams);
const allowedOrigin = process.env.APP_URL || "http://localhost:3000";
let allowedOrigin = process.env.APP_URL;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

Trimming the APP_URL environment variable prevents potential issues caused by accidental leading or trailing whitespace in configuration files, which could otherwise result in malformed font URLs or failed origin validation checks.

Suggested change
let allowedOrigin = process.env.APP_URL;
let allowedOrigin = process.env.APP_URL?.trim();

@codecov

codecov Bot commented Jun 12, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

Comment thread src/app/api/card/[username]/route.ts
Comment thread src/app/api/card/[username]/route.ts
@pull-request-size pull-request-size Bot added size/M and removed size/XS labels Jul 8, 2026
@is0692vs

is0692vs commented Jul 8, 2026

Copy link
Copy Markdown
Contributor Author

@greptile review

Co-authored-by: is0692vs <135803462+is0692vs@users.noreply.github.com>
@pull-request-size pull-request-size Bot added size/XS and removed size/M labels Jul 8, 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: 2

🤖 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 `@src/app/api/card/`[username]/route.ts:
- Around line 22-23: In the route handler for card rendering, replace the
plain-text production 500 response with the same SVG error fallback used by the
other error paths via renderErrorCardResponse, so the response format stays
consistent for embedded <img> usage. Also remove the internal APP_URL detail
from the message by using a generic server configuration error string, and make
sure the 500 response includes the same Cache-Control behavior as the rest of
the image route; if renderErrorCardResponse needs a fontUrl, update its call or
signature in a way that works without exposing APP_URL.
- Around line 20-26: Add a test for the production-only early return in the card
route when APP_URL is missing. Update the route logic in route.ts’s
allowedOrigin handling only if needed, and cover the branch where
process.env.NODE_ENV is "production" and process.env.APP_URL is unset so the
handler returns a 500 Response with the server configuration error message. Use
the existing route handler symbols in src/app/api/card/[username]/route.ts and
mirror the style of route.test.ts to assert this fallback path directly.
🪄 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: ASSERTIVE

Plan: Pro

Run ID: 7787d9d2-18dd-4d18-a60c-2911d96f7591

📥 Commits

Reviewing files that changed from the base of the PR and between a475ecb and a6e198e.

📒 Files selected for processing (1)
  • src/app/api/card/[username]/route.ts

Comment on lines +20 to +26
let allowedOrigin = process.env.APP_URL;
if (!allowedOrigin) {
if (process.env.NODE_ENV === "production") {
return new Response("Server configuration error: APP_URL environment variable is not set", { status: 500 });
}
allowedOrigin = "http://localhost:3000";
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: route.test.ts で allowedOrigin フォールバックロジックのテストを確認

# テストファイルの内容を確認
cat -n src/app/api/card/[username]/route.test.ts

Repository: Hiroki-org/github-user-summary

Length of output: 6312


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# route.ts の分岐と、関連テストの有無を確認
cat -n src/app/api/card/[username]/route.ts
printf '\n---\n'
rg -n "APP_URL|localhost:3000|Server configuration error: APP_URL" src/app/api/card -S
printf '\n---\n'
rg -n "NODE_ENV|production|allowedOrigin|fontUrl" src/app/api/card/[username] -S

Repository: Hiroki-org/github-user-summary

Length of output: 4442


NODE_ENV=production の 500 パスを追加してください。
route.test.ts では localhost フォールバック側は踏めていますが、APP_URL 未設定かつ production 時の早期 500 リターンは未カバーです。

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

In `@src/app/api/card/`[username]/route.ts around lines 20 - 26, Add a test for
the production-only early return in the card route when APP_URL is missing.
Update the route logic in route.ts’s allowedOrigin handling only if needed, and
cover the branch where process.env.NODE_ENV is "production" and
process.env.APP_URL is unset so the handler returns a 500 Response with the
server configuration error message. Use the existing route handler symbols in
src/app/api/card/[username]/route.ts and mirror the style of route.test.ts to
assert this fallback path directly.

Comment on lines +22 to +23
if (process.env.NODE_ENV === "production") {
return new Response("Server configuration error: APP_URL environment variable is not set", { status: 500 });

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

500レスポンスに情報漏洩、フォーマット不整合、キャッシュヘッダー欠落の3つの問題があります。

  1. 情報漏洩: エラーメッセージ "Server configuration error: APP_URL environment variable is not set" が内部環境変数名 APP_URL を露出しています。"Server configuration error" のような汎用メッセージを使用してください。

  2. レスポンスフォーマット不整合: このエンドポイントは画像(SVGカード)を返すルートですが、500レスポンスはプレーンテキストです。他のすべてのエラーパス(行33, 47, 65)は renderErrorCardResponse でSVGを返しています。<img> タグで埋め込まれている場合、プレーンテキストの500は表示を破壊します。

  3. キャッシュヘッダー欠落: 500レスポンスに Cache-Control ヘッダーが設定されていません。CDNやブラウザがこのエラーをキャッシュする可能性があります。As per coding guidelines、src/app/api/card/**/*.{ts,tsx} では「Image routes should preserve cache headers and predictable fallback behavior」が求められています。

renderErrorCardResponse を使用する場合、fontUrlallowedOrigin に依存するため、fontUrl なしで呼び出すかフォールバック値を使用する必要があります。renderErrorCardResponse のシグネチャを確認してください。

🔧 提案する修正
     if (process.env.NODE_ENV === "production") {
-        return new Response("Server configuration error: APP_URL environment variable is not set", { status: 500 });
+        return renderErrorCardResponse({
+            message: "Server configuration error",
+            options,
+            status: 500,
+            cacheControl: ERROR_CACHE,
+        });
     }

renderErrorCardResponsefontUrl なしで動作するか確認してください。fontUrl が必須の場合は、デフォルト値の追加またはシグネチャの調整が必要です。

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (process.env.NODE_ENV === "production") {
return new Response("Server configuration error: APP_URL environment variable is not set", { status: 500 });
if (process.env.NODE_ENV === "production") {
return renderErrorCardResponse({
message: "Server configuration error",
options,
status: 500,
cacheControl: ERROR_CACHE,
});
🤖 Prompt for 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.

In `@src/app/api/card/`[username]/route.ts around lines 22 - 23, In the route
handler for card rendering, replace the plain-text production 500 response with
the same SVG error fallback used by the other error paths via
renderErrorCardResponse, so the response format stays consistent for embedded
<img> usage. Also remove the internal APP_URL detail from the message by using a
generic server configuration error string, and make sure the 500 response
includes the same Cache-Control behavior as the rest of the image route; if
renderErrorCardResponse needs a fontUrl, update its call or signature in a way
that works without exposing APP_URL.

Source: Coding guidelines

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working size/XS

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant