feat: make CORS origin configurable for cloud deployments#2344
Conversation
The JSON-RPC server in jsonrpc.rs hardcodes Access-Control-Allow-Origin to wildcard (*). This is correct for the local/Tauri desktop case (the sidecar only binds to 127.0.0.1) but becomes a security concern when deploying to Docker or cloud where OPENHUMAN_CORE_HOST=0.0.0.0 — any website could make cross-origin requests to the API. Add OPENHUMAN_CORS_ORIGIN env var support: - Default (unset): wildcard *, preserving current desktop behavior - Set to a specific origin: restricts CORS to that origin - Invalid value: falls back to wildcard with no server crash Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
📝 WalkthroughWalkthroughThis PR makes the JSON-RPC server's CORS origin configurable via the ChangesConfigurable CORS Origin
Estimated code review effort🎯 2 (Simple) | ⏱️ ~8 minutes Possibly related issues
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. 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. Comment |
There was a problem hiding this comment.
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 `@src/core/jsonrpc.rs`:
- Around line 626-635: Add structured logging around the CORS origin parsing:
when reading OPENHUMAN_CORS_ORIGIN and before calling
HeaderValue::from_str(&origin) emit an info/debug log that a custom origin was
configured (include the origin value), and when HeaderValue::from_str(&origin)
returns Err (the current unwrap_or_else branch that creates
HeaderValue::from_static("*")) emit a warning/error log that the provided
OPENHUMAN_CORS_ORIGIN was invalid and the code is falling back to wildcard "*"
(include the invalid origin and the fact that wildcard is used); place these
logs adjacent to the origin/origin_value logic and keep using the same logging
facility used elsewhere in jsonrpc.rs for consistent structured, grep-friendly
messages.
🪄 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: 72f12ddd-fdf4-4125-9181-7d0429df60c6
📒 Files selected for processing (2)
.env.examplesrc/core/jsonrpc.rs
| let origin = std::env::var("OPENHUMAN_CORS_ORIGIN") | ||
| .ok() | ||
| .filter(|v| !v.is_empty()) | ||
| .unwrap_or_else(|| "*".to_string()); | ||
| // HeaderValue::from_str is fallible for non-visible ASCII; fall back to | ||
| // wildcard on invalid input so the server never refuses to start over a | ||
| // typo in the env var. | ||
| let origin_value = HeaderValue::from_str(&origin) | ||
| .unwrap_or_else(|_| HeaderValue::from_static("*")); | ||
| headers.insert(header::ACCESS_CONTROL_ALLOW_ORIGIN, origin_value); |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify HeaderValue::from_str usage is correct for the axum version
# Check Cargo.toml for axum version
echo "=== Checking axum version in Cargo.toml ==="
rg -n "axum\s*=" Cargo.toml
# Check for existing HeaderValue::from_str usage patterns in the codebase
echo -e "\n=== Existing HeaderValue::from_str usage ==="
rg -n "HeaderValue::from_str" --type rust -C2Repository: tinyhumansai/openhuman
Length of output: 5383
🏁 Script executed:
# Check the actual current code at lines 626-635
sed -n '620,640p' src/core/jsonrpc.rs | cat -nRepository: tinyhumansai/openhuman
Length of output: 1221
🏁 Script executed:
# Check if log/tracing is already imported in jsonrpc.rs
head -50 src/core/jsonrpc.rs | grep -E "^use.*log|^use.*tracing"Repository: tinyhumansai/openhuman
Length of output: 48
🏁 Script executed:
# Check the full context around the CORS function
sed -n '620,645p' src/core/jsonrpc.rs | cat -nRepository: tinyhumansai/openhuman
Length of output: 1434
🏁 Script executed:
# Check if log crate is in Cargo.toml
rg -n "^log\s*=" Cargo.tomlRepository: tinyhumansai/openhuman
Length of output: 81
🏁 Script executed:
# Search for any logging already in jsonrpc.rs
rg -n "log::|tracing::|eprintln|println" src/core/jsonrpc.rsRepository: tinyhumansai/openhuman
Length of output: 5548
🏁 Script executed:
# Check what's imported at the top of jsonrpc.rs
head -100 src/core/jsonrpc.rsRepository: tinyhumansai/openhuman
Length of output: 4566
Add logging for CORS origin validation to improve observability.
The CORS header configuration should log when an invalid OPENHUMAN_CORS_ORIGIN environment variable falls back to wildcard *, as this is a security-relevant error path for cloud deployments. Also log when a valid custom origin is configured.
Add structured, grep-friendly logging consistent with the rest of jsonrpc.rs:
Suggested logging implementation
let origin_value = HeaderValue::from_str(&origin)
- .unwrap_or_else(|_| HeaderValue::from_static("*"));
+ .unwrap_or_else(|e| {
+ log::warn!(
+ "[cors] Invalid OPENHUMAN_CORS_ORIGIN value {:?} — falling back to wildcard '*': {}",
+ origin,
+ e
+ );
+ HeaderValue::from_static("*")
+ });
+ if origin != "*" && origin_value.to_str().unwrap_or("*") != "*" {
+ log::debug!("[cors] Using custom origin: {}", origin);
+ }Per coding guidelines, error paths should be logged at appropriate levels. The fallback to wildcard when invalid input is provided is a security-relevant error path that operators need to observe.
📝 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.
| let origin = std::env::var("OPENHUMAN_CORS_ORIGIN") | |
| .ok() | |
| .filter(|v| !v.is_empty()) | |
| .unwrap_or_else(|| "*".to_string()); | |
| // HeaderValue::from_str is fallible for non-visible ASCII; fall back to | |
| // wildcard on invalid input so the server never refuses to start over a | |
| // typo in the env var. | |
| let origin_value = HeaderValue::from_str(&origin) | |
| .unwrap_or_else(|_| HeaderValue::from_static("*")); | |
| headers.insert(header::ACCESS_CONTROL_ALLOW_ORIGIN, origin_value); | |
| let origin = std::env::var("OPENHUMAN_CORS_ORIGIN") | |
| .ok() | |
| .filter(|v| !v.is_empty()) | |
| .unwrap_or_else(|| "*".to_string()); | |
| // HeaderValue::from_str is fallible for non-visible ASCII; fall back to | |
| // wildcard on invalid input so the server never refuses to start over a | |
| // typo in the env var. | |
| let origin_value = HeaderValue::from_str(&origin) | |
| .unwrap_or_else(|e| { | |
| log::warn!( | |
| "[cors] Invalid OPENHUMAN_CORS_ORIGIN value {:?} — falling back to wildcard '*': {}", | |
| origin, | |
| e | |
| ); | |
| HeaderValue::from_static("*") | |
| }); | |
| if origin != "*" && origin_value.to_str().unwrap_or("*") != "*" { | |
| log::debug!("[cors] Using custom origin: {}", origin); | |
| } | |
| headers.insert(header::ACCESS_CONTROL_ALLOW_ORIGIN, origin_value); |
🧰 Tools
🪛 GitHub Actions: Type Check / 0_Type Check TypeScript.txt
[error] 630-630: Prettier formatting check failed. Diff indicates a formatting change in jsonrpc.rs around let origin_value = HeaderValue::from_str(&origin) ... (reflowed to multiple lines).
🪛 GitHub Actions: Type Check / 1_Rust Quality (fmt + clippy).txt
[error] 630-631: cargo fmt --all -- --check failed due to formatting diff in src/core/jsonrpc.rs around line 630 (mismatched line breaks/indentation). Run cargo fmt to apply the correct formatting.
🪛 GitHub Actions: Type Check / Rust Quality (fmt + clippy)
[error] 630-632: cargo fmt --check failed due to Rust formatting differences. Diff indicates formatting change needed for let origin_value assignment (line break/indentation).
🪛 GitHub Actions: Type Check / Type Check TypeScript
[error] 630-634: Prettier format check failed. Diff shows formatting change in let origin_value assignment (line wrapping/indentation).
🤖 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/core/jsonrpc.rs` around lines 626 - 635, Add structured logging around
the CORS origin parsing: when reading OPENHUMAN_CORS_ORIGIN and before calling
HeaderValue::from_str(&origin) emit an info/debug log that a custom origin was
configured (include the origin value), and when HeaderValue::from_str(&origin)
returns Err (the current unwrap_or_else branch that creates
HeaderValue::from_static("*")) emit a warning/error log that the provided
OPENHUMAN_CORS_ORIGIN was invalid and the code is falling back to wildcard "*"
(include the invalid origin and the fact that wildcard is used); place these
logs adjacent to the origin/origin_value logic and keep using the same logging
facility used elsewhere in jsonrpc.rs for consistent structured, grep-friendly
messages.
|
@hobostay CI is failing on changes in this PR — please fix before review. |
2 similar comments
|
@hobostay CI is failing on changes in this PR — please fix before review. |
|
@hobostay CI is failing on changes in this PR — please fix before review. |
Summary
OPENHUMAN_CORS_ORIGINenvironment variable to configure the JSON-RPC server'sAccess-Control-Allow-Originheader*for local/Tauri desktophttps://app.example.com), CORS is restricted to that origin onlyContext
The JSON-RPC server in
src/core/jsonrpc.rshardcodesAccess-Control-Allow-Origin: *. This is correct for the desktop case where the sidecar binds to127.0.0.1, but becomes a security concern for Docker/cloud deployments whereOPENHUMAN_CORE_HOST=0.0.0.0— any website could make cross-origin requests to the API.The
.env.examplealready documents cloud deployment mode (OPENHUMAN_CORE_HOST=0.0.0.0) andgitbooks/features/cloud-deploy.mdcovers the setup. This change gives cloud deployers the ability to lock down CORS without modifying source code.Test plan
OPENHUMAN_CORS_ORIGINunset (wildcard)OPENHUMAN_CORS_ORIGIN=https://example.comand verify CORS header reflects the valueOPENHUMAN_CORS_ORIGINto an invalid string and verify fallback to wildcard🤖 Generated with Claude Code
Summary by CodeRabbit
Release Notes