mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-08-18 16:02:10 +00:00
fix(ai): validate token_url for SSRF in OAuth credentials flow (#9385)
get_token_using_oauth resolved the AI OAuth resource's token_url and POSTed to it without any SSRF validation, while base_url is validated in get_base_url. A workspace member with resources:write could point token_url at an internal/metadata address (e.g. 169.254.169.254), turning the server into an authenticated blind SSRF probe. Validate the resolved token_url with validate_url_for_ssrf before the request, gated behind the same ALLOW_PRIVATE_AI_BASE_URLS opt-in as base_url so private AI deployments keep working consistently for both URL fields. ALLOW_PRIVATE_AI_BASE_URLS is now pub so windmill-api can reuse it instead of re-parsing the env var.
This commit is contained in:
@@ -20,7 +20,7 @@ where
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
static ref OPENAI_AZURE_BASE_PATH: Option<String> = std::env::var("OPENAI_AZURE_BASE_PATH").ok();
|
||||
static ref ALLOW_PRIVATE_AI_BASE_URLS: bool = std::env::var("ALLOW_PRIVATE_AI_BASE_URLS")
|
||||
pub static ref ALLOW_PRIVATE_AI_BASE_URLS: bool = std::env::var("ALLOW_PRIVATE_AI_BASE_URLS")
|
||||
.ok()
|
||||
.map(|v| v == "true" || v == "1")
|
||||
.unwrap_or(false);
|
||||
|
||||
@@ -305,6 +305,22 @@ async fn get_token_using_oauth(
|
||||
resource.client_id = resolve_var(resource.client_id, db, w_id, user_db, authed).await?;
|
||||
resource.client_secret = resolve_var(resource.client_secret, db, w_id, user_db, authed).await?;
|
||||
resource.token_url = resolve_var(resource.token_url, db, w_id, user_db, authed).await?;
|
||||
// Validate the resolved token_url against SSRF rules before issuing the request,
|
||||
// mirroring the protection applied to base_url in `get_base_url` (same
|
||||
// ALLOW_PRIVATE_AI_BASE_URLS opt-in). Without this a workspace member could
|
||||
// point token_url at an internal/metadata address.
|
||||
if !*windmill_ai::ai_providers::ALLOW_PRIVATE_AI_BASE_URLS {
|
||||
use windmill_common::ssrf::SsrfValidationError;
|
||||
windmill_common::ssrf::validate_url_for_ssrf(&resource.token_url)
|
||||
.await
|
||||
.map_err(|e| match e {
|
||||
e @ SsrfValidationError::Private { .. } => Error::BadRequest(format!(
|
||||
"{e}. If you need to use private/internal AI endpoints, \
|
||||
set the ALLOW_PRIVATE_AI_BASE_URLS=true environment variable"
|
||||
)),
|
||||
e => Error::from(e),
|
||||
})?;
|
||||
}
|
||||
let mut params = HashMap::new();
|
||||
params.insert("grant_type", "client_credentials");
|
||||
params.insert("scope", "https://cognitiveservices.azure.com/.default");
|
||||
|
||||
Reference in New Issue
Block a user