You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This PR hardens the Vikingbot HTTP OpenAPI surface so privileged chat and session endpoints fail closed unless an explicit API key is configured.
require a configured api_key for /bot/v1/chat, /bot/v1/chat/stream, /bot/v1/sessions, and related session-management routes
require a configured per-channel api_key for /bot/v1/chat/channel and /bot/v1/chat/channel/stream
keep /bot/v1/health available without authentication
add focused regression tests covering fail-closed and valid-key behavior for both endpoint families
Security issues covered
Issue
Impact
Severity
OpenAPI HTTP routes accept requests when api_key is unset
Unauthenticated users can drive the bot over HTTP and create/list/use sessions
High
Per-channel bot routes accept requests when per-channel api_key is unset
Unauthenticated users can invoke specific bot channels over HTTP
High
Before this PR
an empty OpenAPI api_key allowed /chat, /chat/stream, and session routes without authentication
an empty per-channel bot api_key allowed /chat/channel and /chat/channel/stream without authentication
gateway startup paths still enabled the HTTP surface even when no API key had been configured
After this PR
privileged HTTP chat and session routes return 503 until an operator configures an API key
requests with a missing or wrong X-API-Key continue to return 401 or 403
/health remains unauthenticated so operators can still probe service readiness safely
regression tests lock in both the fail-closed default and the valid-key success path
Why this matters
The bot HTTP API is a control-plane surface, not a public read-only status endpoint. Once exposed, it can submit attacker-controlled prompts into the bot bus, create and inspect bot sessions, and reach whatever downstream tools or integrations the bot operator enabled. That boundary should require explicit operator intent.
Attack flow
unauthenticated HTTP request
-> Vikingbot OpenAPI router
-> fail-open auth check when api_key is empty
-> bot message/session processing without authentication
Affected code
Surface
Files
OpenAPI auth enforcement
bot/vikingbot/channels/openapi.py
Gateway startup defaults / operator messaging
bot/vikingbot/cli/commands.py
config semantics documentation
bot/vikingbot/config/schema.py
regression coverage
bot/tests/test_openapi_auth.py
Root cause
the OpenAPI route dependency treated an empty api_key as allow all
per-channel bot routes used the same trust model and skipped auth when a channel key was unset
CLI startup enabled the HTTP surface without making the secure requirement explicit
CVSS assessment
Issue
CVSS v3.1
Vector
Unauthenticated HTTP bot access when API keys are unset
8.8 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:L
|
Per-channel unauthenticated HTTP bot access when channel keys are unset | 8.8 High | CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:L |
Rationale:
network reachable
no prior authentication required
attacker-controlled prompts can reach the bot workflow directly
confidentiality and integrity impact depend on enabled bot capabilities, but the trust-boundary break is clear even in minimal deployments
Safe reproduction steps
Start Vikingbot with the OpenAPI HTTP surface enabled and no configured API key.
Send POST /bot/v1/chat with a JSON body like {"message": "hello"} and no X-API-Key header.
Observe that vulnerable code accepts the request and processes it through the bot pipeline.
Apply this patch and repeat the same request.
Observe the patched behavior returns 503 until an API key is explicitly configured.
Configure an API key and repeat with the correct X-API-Key header.
Observe the request succeeds again.
Expected vulnerable behavior
/bot/v1/chat and /bot/v1/chat/stream accept requests when api_key is empty
/bot/v1/sessions and related session routes accept unauthenticated access when api_key is empty
/bot/v1/chat/channel and /bot/v1/chat/channel/stream accept unauthenticated access when a bot channel api_key is empty
Changes in this PR
change the OpenAPI auth dependency to reject privileged HTTP routes when the gateway api_key is unset
change per-channel bot route checks to reject access when a channel api_key is unset
update CLI logging to make the API-key requirement explicit when enabling the HTTP surface
update config comments so an empty key is documented as disabled, not unauthenticated
add regression tests for:
open health route without a key
fail-closed chat behavior with no key
successful chat with a valid key
fail-closed bot-channel behavior with no channel key
successful bot-channel request with a valid key
Files changed
Category
Files
What changed
runtime auth
bot/vikingbot/channels/openapi.py
fail closed for unset gateway/channel API keys
startup/operator guidance
bot/vikingbot/cli/commands.py
log that HTTP chat endpoints require configured API keys
config semantics
bot/vikingbot/config/schema.py
document empty keys as disabled routes
tests
bot/tests/test_openapi_auth.py
add focused auth regression coverage
Maintainer impact
patch scope is narrow and isolated to the bot HTTP surface
no changes to the health endpoint or unrelated chat channels
operators who already configured API keys keep the same request flow
operators who relied on empty-key unauthenticated HTTP access now need to make an explicit authentication choice
Fix rationale
Privileged HTTP bot routes should be secure by default. An operator can still expose them intentionally by setting an API key, but the default behavior should not silently create an unauthenticated remote control surface.
Type of change
Bug fix (non-breaking change that hardens existing behavior)
editable-install based uv run test execution in this environment is currently blocked by a pre-existing build issue requiring the ov CLI artifact / Cargo during package build. This patch was validated through direct source-path execution instead.
Disclosure notes
claims in this PR are bounded to the reviewed Vikingbot HTTP route code paths
this patch does not change unrelated OpenViking server authentication behavior
API key verification logic for bot channels is duplicated between chat_channel and chat_channel_stream endpoints. Extracting this into a shared helper function would reduce redundancy and improve maintainability.
# Verify API key for the specific channelbot_config=channel._bot_configs[channel_id]
ifnotbot_config.api_key:
raiseHTTPException(
status_code=503,
detail=f"Bot channel '{channel_id}' API key is not configured",
)
ifnotx_api_key:
raiseHTTPException(status_code=401, detail="X-API-Key header required")
ifnotsecrets.compare_digest(x_api_key, bot_config.api_key):
raiseHTTPException(status_code=403, detail="Invalid API key")
returnawaitchannel._handle_bot_chat(channel_id, request)
@router.post("/chat/channel/stream")asyncdefchat_channel_stream(
request: ChatRequest,
x_api_key: Optional[str] =Depends(verify_bot_channel_api_key),
):
"""Send a chat message to a specific bot channel and get a streaming response."""channel_id=request.channel_idifnotchannel_id:
raiseHTTPException(status_code=400, detail="channel_id is required")
ifchannel_idnotinchannel._bot_configs:
raiseHTTPException(status_code=404, detail=f"Channel '{channel_id}' not found")
# Verify API key for the specific channelbot_config=channel._bot_configs[channel_id]
ifnotbot_config.api_key:
raiseHTTPException(
status_code=503,
detail=f"Bot channel '{channel_id}' API key is not configured",
)
ifnotx_api_key:
raiseHTTPException(status_code=401, detail="X-API-Key header required")
ifnotsecrets.compare_digest(x_api_key, bot_config.api_key):
raiseHTTPException(status_code=403, detail="Invalid API key")
Extract the duplicated bot channel API key verification logic into a helper function to avoid code duplication between chat_channel and chat_channel_stream endpoints. This improves maintainability and ensures consistent behavior across both endpoints.
-# Verify API key for the specific channel-bot_config = channel._bot_configs[channel_id]-if not bot_config.api_key:- raise HTTPException(- status_code=503,- detail=f"Bot channel '{channel_id}' API key is not configured",- )-if not x_api_key:- raise HTTPException(status_code=401, detail="X-API-Key header required")-if not secrets.compare_digest(x_api_key, bot_config.api_key):- raise HTTPException(status_code=403, detail="Invalid API key")+def _verify_bot_channel_api_key(channel_id: str, x_api_key: Optional[str]) -> None:+ bot_config = channel._bot_configs[channel_id]+ if not bot_config.api_key:+ raise HTTPException(+ status_code=503,+ detail=f"Bot channel '{channel_id}' API key is not configured",+ )+ if not x_api_key:+ raise HTTPException(status_code=401, detail="X-API-Key header required")+ if not secrets.compare_digest(x_api_key, bot_config.api_key):+ raise HTTPException(status_code=403, detail="Invalid API key")+# Then in both endpoints:+_verify_bot_channel_api_key(channel_id, x_api_key)+
Suggestion importance[1-10]: 6
__
Why: The suggestion correctly identifies duplicated bot channel API key verification logic between chat_channel and chat_channel_stream endpoints. Extracting this into a helper improves maintainability and ensures consistent behavior, making it a valid moderate-impact improvement.
Hinotoi-agent
changed the title
fix(bot): require API keys for OpenAPI HTTP routes
[security] fix(bot): require API keys for OpenAPI HTTP routes
Apr 14, 2026
Hinotoi-agent
changed the title
[security] fix(bot): require API keys for OpenAPI HTTP routes
[security] fix(bot): prevent unauthenticated remote bot control via OpenAPI HTTP routes
Apr 14, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR hardens the Vikingbot HTTP OpenAPI surface so privileged chat and session endpoints fail closed unless an explicit API key is configured.
api_keyfor/bot/v1/chat,/bot/v1/chat/stream,/bot/v1/sessions, and related session-management routesapi_keyfor/bot/v1/chat/channeland/bot/v1/chat/channel/stream/bot/v1/healthavailable without authenticationSecurity issues covered
api_keyis unsetapi_keyis unsetBefore this PR
api_keyallowed/chat,/chat/stream, and session routes without authenticationapi_keyallowed/chat/channeland/chat/channel/streamwithout authenticationAfter this PR
503until an operator configures an API keyX-API-Keycontinue to return401or403/healthremains unauthenticated so operators can still probe service readiness safelyWhy this matters
The bot HTTP API is a control-plane surface, not a public read-only status endpoint. Once exposed, it can submit attacker-controlled prompts into the bot bus, create and inspect bot sessions, and reach whatever downstream tools or integrations the bot operator enabled. That boundary should require explicit operator intent.
Attack flow
Affected code
bot/vikingbot/channels/openapi.pybot/vikingbot/cli/commands.pybot/vikingbot/config/schema.pybot/tests/test_openapi_auth.pyRoot cause
api_keyasallow allCVSS assessment
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:L|
Per-channel unauthenticated HTTP bot access when channel keys are unset | 8.8 High |
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:L|Rationale:
Safe reproduction steps
POST /bot/v1/chatwith a JSON body like{"message": "hello"}and noX-API-Keyheader.503until an API key is explicitly configured.X-API-Keyheader.Expected vulnerable behavior
/bot/v1/chatand/bot/v1/chat/streamaccept requests whenapi_keyis empty/bot/v1/sessionsand related session routes accept unauthenticated access whenapi_keyis empty/bot/v1/chat/channeland/bot/v1/chat/channel/streamaccept unauthenticated access when a bot channelapi_keyis emptyChanges in this PR
api_keyis unsetapi_keyis unsetFiles changed
bot/vikingbot/channels/openapi.pybot/vikingbot/cli/commands.pybot/vikingbot/config/schema.pybot/tests/test_openapi_auth.pyMaintainer impact
Fix rationale
Privileged HTTP bot routes should be secure by default. An operator can still expose them intentionally by setting an API key, but the default behavior should not silently create an unauthenticated remote control surface.
Type of change
Test plan
PYTHONPATH=.:bot /Users/lennon/.hermes/hermes-agent/venv/bin/python -m py_compile bot/vikingbot/channels/openapi.py bot/vikingbot/cli/commands.py bot/vikingbot/config/schema.py bot/tests/test_openapi_auth.pyPYTHONPATH=.:bot /Users/lennon/.hermes/hermes-agent/venv/bin/python -m pytest -o addopts='' bot/tests/test_openapi_auth.py -qTargeted test result:
5 passedNote:
uv runtest execution in this environment is currently blocked by a pre-existing build issue requiring theovCLI artifact / Cargo during package build. This patch was validated through direct source-path execution instead.Disclosure notes