Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions crates/trusted-server-adapter-axum/tests/routes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ async fn aps_profile_serves_renderer_through_adapter_fallback() {
settings.auction.providers.insert(
"aps-main".parse().expect("should parse APS provider ID"),
trusted_server_core::auction::ProviderConfig {
allow_insecure_http: false,
protocol: "openrtb-2.6".to_string(),
profile: "aps".to_string(),
endpoint: "https://aps.example/e/pb/bid".to_string(),
Expand Down
3 changes: 3 additions & 0 deletions crates/trusted-server-adapter-cloudflare/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -847,6 +847,7 @@ mod tests {
settings.auction.providers.insert(
"aps-main".parse().expect("should parse APS provider ID"),
trusted_server_core::auction::ProviderConfig {
allow_insecure_http: false,
protocol: "openrtb-2.6".to_string(),
profile: "aps".to_string(),
endpoint: "https://aps.example/e/pb/bid".to_string(),
Expand Down Expand Up @@ -913,6 +914,7 @@ mod tests {
(
id.parse().expect("should parse provider ID"),
trusted_server_core::auction::ProviderConfig {
allow_insecure_http: false,
protocol: "openrtb-2.6".to_string(),
profile: "standard".to_string(),
endpoint: format!("https://{id}.example/openrtb"),
Expand Down Expand Up @@ -957,6 +959,7 @@ mod tests {
(
id.parse().expect("should parse provider ID"),
trusted_server_core::auction::ProviderConfig {
allow_insecure_http: false,
protocol: "openrtb-2.6".to_string(),
profile: "standard".to_string(),
endpoint: format!("https://{id}.example/openrtb"),
Expand Down
1 change: 1 addition & 0 deletions crates/trusted-server-adapter-fastly/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1829,6 +1829,7 @@ mod tests {
settings.auction.providers.insert(
"aps-main".parse().expect("should parse APS provider ID"),
trusted_server_core::auction::ProviderConfig {
allow_insecure_http: false,
protocol: "openrtb-2.6".to_string(),
profile: "aps".to_string(),
endpoint: "https://aps.example/e/pb/bid".to_string(),
Expand Down
2 changes: 2 additions & 0 deletions crates/trusted-server-adapter-spin/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1038,6 +1038,7 @@ mod tests {
(
id.parse().expect("should parse provider ID"),
trusted_server_core::auction::ProviderConfig {
allow_insecure_http: false,
protocol: "openrtb-2.6".to_string(),
profile: "standard".to_string(),
endpoint: format!("https://{id}.example/openrtb"),
Expand All @@ -1062,6 +1063,7 @@ mod tests {
settings.auction.providers.insert(
"aps-main".parse().expect("should parse APS provider ID"),
trusted_server_core::auction::ProviderConfig {
allow_insecure_http: false,
protocol: "openrtb-2.6".to_string(),
profile: "aps".to_string(),
endpoint: "https://aps.example/e/pb/bid".to_string(),
Expand Down
1 change: 1 addition & 0 deletions crates/trusted-server-core/src/auction/formats.rs
Original file line number Diff line number Diff line change
Expand Up @@ -625,6 +625,7 @@ mod tests {
providers: BTreeMap::from([(
ProviderId::from_str("pbs-primary").expect("should parse provider ID"),
ProviderConfig {
allow_insecure_http: false,
protocol: "openrtb-2.6".to_string(),
profile: "prebid-server".to_string(),
endpoint: "https://pbs.example.test/openrtb".to_string(),
Expand Down
1 change: 1 addition & 0 deletions crates/trusted-server-core/src/auction/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@ mod plan_sharing_tests {
settings.auction.providers = std::collections::BTreeMap::from([(
"aps-main".parse().expect("should parse APS provider ID"),
ProviderConfig {
allow_insecure_http: false,
protocol: "openrtb-2.6".to_string(),
profile: "aps".to_string(),
endpoint: "https://aps.example/e/pb/bid".to_string(),
Expand Down
1 change: 1 addition & 0 deletions crates/trusted-server-core/src/auction/openrtb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -960,6 +960,7 @@ mod routing_metadata_tests {
providers: BTreeMap::from([(
provider_id.clone(),
ProviderConfig {
allow_insecure_http: false,
protocol: "openrtb-2.6".to_string(),
profile: profile.to_string(),
endpoint: if profile == "aps" {
Expand Down
1 change: 1 addition & 0 deletions crates/trusted-server-core/src/auction/openrtb/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ fn config_with_endpoint(profile: &str, profile_config: Value, endpoint: &str) ->
providers: BTreeMap::from([(
provider_id.clone(),
ProviderConfig {
allow_insecure_http: false,
protocol: "openrtb-2.6".to_string(),
profile: profile.to_string(),
endpoint: endpoint.to_string(),
Expand Down
3 changes: 3 additions & 0 deletions crates/trusted-server-core/src/auction/orchestrator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2835,6 +2835,7 @@ mod tests {
(
ProviderId::from_str(id).expect("should parse fictional provider ID"),
ProviderConfig {
allow_insecure_http: false,
protocol: "openrtb-2.6".to_string(),
profile: "standard".to_string(),
endpoint: "https://example.test/openrtb".to_string(),
Expand Down Expand Up @@ -2867,6 +2868,7 @@ mod tests {
(
ProviderId::from_str(id).expect("should parse fictional provider ID"),
ProviderConfig {
allow_insecure_http: false,
protocol: "openrtb-2.6".to_string(),
profile: "prebid-server".to_string(),
endpoint: format!("https://{id}.example.test/openrtb"),
Expand Down Expand Up @@ -2903,6 +2905,7 @@ mod tests {
(
ProviderId::from_str(id).expect("should parse fictional provider ID"),
ProviderConfig {
allow_insecure_http: false,
protocol: "openrtb-2.6".to_string(),
profile: "aps".to_string(),
endpoint: "https://aps.example/e/pb/bid".to_string(),
Expand Down
95 changes: 93 additions & 2 deletions crates/trusted-server-core/src/auction/plan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,10 @@ pub struct ProviderConfig {
pub profile: String,
/// Fixed provider endpoint.
pub endpoint: String,
/// Permit unencrypted HTTP for this provider only. Defaults to false.
/// Use only for explicitly approved demo/test endpoints.
Comment on lines +138 to +139

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

♻️ refactor: Split the summary from the details per AGENTS.md, and say why the field is skipped while false. The sibling fields that use the same pattern (Publisher::allow_async_html_finish and DebugConfig::sandbox_metrics_enabled in settings.rs) document the rollback consequence. It applies here too, because ProviderConfig denies unknown fields.

Suggested change
/// Permit unencrypted HTTP for this provider only. Defaults to false.
/// Use only for explicitly approved demo/test endpoints.
/// Permit an unencrypted `http` endpoint for this provider only.
///
/// Defaults to false. Use only for explicitly approved demo/test endpoints:
/// requests to this provider carry client IP, geo, consent signals and
/// identifiers in cleartext, and its responses can be altered in transit.
///
/// Skipped from serialization while false: [`ProviderConfig`] denies
/// unknown fields, so a default blob stays readable by a binary built
/// before this field existed. A blob with it enabled requires restoring a
/// compatible blob before rolling back.

#[serde(default, skip_serializing_if = "is_false")]

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

👍 praise — skip_serializing_if = "is_false" keeps the serialized config byte-identical for every existing provider, and insecure_http_default_preserves_existing_provider_wire_shape pins that. Nice care for published config blobs.

pub allow_insecure_http: bool,
/// Optional profile-default timeout override.
#[serde(default)]
pub timeout_ms: Option<u32>,
Expand Down Expand Up @@ -314,7 +318,12 @@ impl AuctionPlan {
"provider `{id}` profile_config must be an object"
)));
}
let endpoint = canonicalize_endpoint(&id, registration.id, &raw.endpoint)?;
let endpoint = canonicalize_endpoint(
&id,
registration.id,
&raw.endpoint,
raw.allow_insecure_http,
)?;
Comment on lines +321 to +326

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🔧 wrench: Nothing tells the operator that a provider is running in plaintext.

An opted-in provider's requests carry the client IP (device.ip, plus X-Forwarded-For for the prebid-server profile), geo (lat/lon for PBS), User-Agent, the TCF string and consent cookies, and the EC ID and EIDs when present. Its responses (price, adm, nurl/burl) can be rewritten in transit, and sanitize_creatives defaults to off. I ran opted-in configs end to end on Axum and on Fastly under Viceroy. ts config validate, ts config push and the adapter runtime all stayed silent while the stub bidder received a plaintext POST /openrtb2/auction carrying those fields.

The repo already warns for the equivalent publisher-origin case (publisher_origin_diagnostics, config.rs:89). Logging at plan compile covers deploy validation and every adapter's startup from one place. On Fastly it fires once per instance, like the public_origin warning. CodeQL may flag the new log site as rust/cleartext-logging (Settings taint); the comment follows the convention at the orchestrator's provider-ID log sites. The CLI installs no logger, so this reaches adapter logs only (see the 📌 in the review body).

Suggested change
let endpoint = canonicalize_endpoint(
&id,
registration.id,
&raw.endpoint,
raw.allow_insecure_http,
)?;
let endpoint = canonicalize_endpoint(
&id,
registration.id,
&raw.endpoint,
raw.allow_insecure_http,
)?;
if endpoint.url().scheme() == "http" {
// This logs a configured provider identifier, not request data or secrets.
log::warn!(
"provider `{id}` uses unencrypted HTTP; its requests carry client IP, geo, consent signals and identifiers in cleartext, and its responses can be altered in transit"
);
}

let timeout_ms = raw
.timeout_ms
.unwrap_or(match registration.default_timeout {
Expand Down Expand Up @@ -566,13 +575,14 @@ fn canonicalize_endpoint(
provider_id: &ProviderId,
profile_id: &str,
value: &str,
allow_insecure_http: bool,
) -> Result<CanonicalProviderEndpoint, Report<TrustedServerError>> {
let mut endpoint = Url::parse(value).map_err(|error| {
configuration_error(format!(
"provider `{provider_id}` endpoint must be an absolute HTTPS URL: {error}"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

⛏ nitpick — Both endpoint errors still say HTTPS is required, which misleads an operator who set allow_insecure_http = true and then hits a parse or credentials/fragment failure. This first message fires on parse failure only, so the scheme isn't the issue there:

Suggested change
"provider `{provider_id}` endpoint must be an absolute HTTPS URL: {error}"
"provider `{provider_id}` endpoint must be an absolute URL: {error}"

The second message at line 592 (outside the diff hunk, so no one-click suggestion) could become something like "provider {provider_id} endpoint must be absolute HTTPS (or HTTP when allow_insecure_http is set) with a host and no credentials or fragment". Apply manually.

))
})?;
if endpoint.scheme() != "https"
if !(endpoint.scheme() == "https" || (allow_insecure_http && endpoint.scheme() == "http"))

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

⛏ nitpick: For an opted-in provider, a rejected http:// endpoint (for example http://user:pass@pbs.example.com/bid) still gets endpoint must be absolute HTTPS with a host and no credentials or fragment from line 592. That reads as if the scheme were the problem. Consider wording that covers both schemes, for example:

"provider `{provider_id}` endpoint must be an absolute HTTPS URL, or HTTP when allow_insecure_http is set, with a host and no credentials or fragment"

docs/guide/error-reference.md documents this error family, so update it alongside. Apply manually: line 592 is outside the diff hunk.

|| endpoint.host_str().is_none()
|| !endpoint.username().is_empty()
|| endpoint.password().is_some()
Expand All @@ -598,6 +608,10 @@ fn canonicalize_endpoint(
Ok(CanonicalProviderEndpoint(endpoint))
}

fn is_false(value: &bool) -> bool {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

♻️ refactor: settings.rs:2822 already defines the same is_false serde predicate, with a doc comment. Make that one pub(crate) and point this field at it, so the two can't drift:

// settings.rs
/// Serde predicate for omitting `false` flags from serialized config blobs.
pub(crate) fn is_false(value: &bool) -> bool {
    !*value
}
// plan.rs
#[serde(default, skip_serializing_if = "crate::settings::is_false")]
pub allow_insecure_http: bool,

Then delete this copy. Apply manually: the fix touches settings.rs, which is outside this diff.

!*value
}

fn normalize_prebid_server_endpoint(endpoint: &mut Url) {
match endpoint.path() {
"" | "/" => endpoint.set_path("/openrtb2/auction"),
Expand Down Expand Up @@ -644,6 +658,7 @@ mod tests {

fn provider(profile: &str) -> ProviderConfig {
ProviderConfig {
allow_insecure_http: false,
protocol: "openrtb-2.6".to_string(),
profile: profile.to_string(),
endpoint: "https://bid.example/openrtb2/auction".to_string(),
Expand Down Expand Up @@ -1123,6 +1138,82 @@ mod tests {
assert!(AuctionPlan::compile(config(BTreeMap::from([(id("aps"), aps)]))).is_err());
}

#[test]
fn insecure_http_requires_an_explicit_per_provider_opt_in() {
let mut demo = provider("prebid-server");
demo.endpoint = "http://pbs.example.com:8000".to_string();
assert!(
AuctionPlan::compile(config(BTreeMap::from([(id("demo"), demo.clone())]))).is_err(),
"should reject HTTP without the provider's explicit opt-in"
);
demo.allow_insecure_http = true;
let plan = AuctionPlan::compile(config(BTreeMap::from([(id("demo"), demo.clone())])))
.expect("should compile an explicitly opted-in HTTP provider");
assert_eq!(
plan.providers()[0].endpoint.as_str(),
"http://pbs.example.com:8000/openrtb2/auction",
"should normalize the opted-in Prebid Server endpoint"
);
Comment on lines +1152 to +1156

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🔧 wrench: The tests don't check how an opted-in provider is dialed, or that the flag leaves HTTPS alone.

I ran 9 mutants of plan.rs against the full core lib suite. The scope, scheme, credential, fragment and serde mutants are all killed, but two survive:

  • backend_spec_with_transport_timeout hard-coding scheme: "https". Every opted-in HTTP provider would then dial TLS (Fastly registers an https_… backend with enable_ssl), and CI stays green.
  • canonicalize_endpoint calling set_scheme("http") when the flag is set. The spec's "HTTPS is not downgraded when the flag is true" has no test behind it.

With this suggestion applied, both mutants fail this test (should dial the opted-in provider without TLS on its configured port and should not downgrade HTTPS when the provider opts in to HTTP).

Suggested change
assert_eq!(
plan.providers()[0].endpoint.as_str(),
"http://pbs.example.com:8000/openrtb2/auction",
"should normalize the opted-in Prebid Server endpoint"
);
assert_eq!(
plan.providers()[0].endpoint.as_str(),
"http://pbs.example.com:8000/openrtb2/auction",
"should normalize the opted-in Prebid Server endpoint"
);
let spec = plan.providers()[0].backend_spec();
assert_eq!(
(spec.scheme.as_str(), spec.port),
("http", Some(8000)),
"should dial the opted-in provider without TLS on its configured port"
);
plan.validate_for_target(AuctionTargetId::Fastly)
.expect("should predict a Fastly backend for the opted-in HTTP provider");
let mut secure = demo.clone();
secure.endpoint = "https://pbs.example.com".to_string();
let secure_plan = AuctionPlan::compile(config(BTreeMap::from([(id("demo"), secure)])))
.expect("should compile an opted-in HTTPS provider");
assert_eq!(
secure_plan.providers()[0].endpoint.as_str(),
"https://pbs.example.com/openrtb2/auction",
"should not downgrade HTTPS when the provider opts in to HTTP"
);

let mut other = provider("standard");
other.endpoint = "http://other.example.com/bid".to_string();
assert!(
AuctionPlan::compile(config(BTreeMap::from([
(id("demo"), demo),
(id("other"), other)
])))
.is_err(),
"should not inherit another provider's HTTP opt-in"
);
}

#[test]
fn insecure_http_opt_in_does_not_allow_credentials_fragments_or_other_schemes() {
for endpoint in [
"http://user:pass@pbs.example.com/bid",
"http://pbs.example.com/bid#fragment",
"ftp://pbs.example.com/bid",
"/relative",
] {
let mut raw = provider("prebid-server");
raw.allow_insecure_http = true;
raw.endpoint = endpoint.to_string();
assert!(
AuctionPlan::compile(config(BTreeMap::from([(id("demo"), raw)]))).is_err(),
"should reject {endpoint}"
);
}
}

#[test]
fn insecure_http_default_preserves_existing_provider_wire_shape() {
let legacy = serde_json::to_value(provider("prebid-server"))
.expect("should serialize the default provider");
assert!(
legacy.get("allow_insecure_http").is_none(),
"should omit the default HTTP opt-in field"
);
assert!(
!serde_json::from_value::<ProviderConfig>(legacy)
.expect("should deserialize the default provider")
.allow_insecure_http,
"should keep HTTP disabled when the field is absent"
);
let mut opted_in = provider("prebid-server");
opted_in.allow_insecure_http = true;
let encoded =
serde_json::to_value(opted_in).expect("should serialize the opted-in provider");
assert_eq!(
encoded["allow_insecure_http"], true,
"should publish the explicit HTTP opt-in"
);
assert!(
serde_json::from_value::<ProviderConfig>(encoded)
.expect("should deserialize the opted-in provider")
.allow_insecure_http,
"should retain the explicit HTTP opt-in across serialization"
);
}

#[test]
fn compiler_normalizes_only_prebid_server_origin_and_canonical_paths() {
for (configured, expected) in [
Expand Down
1 change: 1 addition & 0 deletions crates/trusted-server-core/src/auction/routing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -579,6 +579,7 @@ mod tests {

fn provider(profile: &str, routing: RoutingMode) -> ProviderConfig {
ProviderConfig {
allow_insecure_http: false,
protocol: "openrtb-2.6".to_string(),
profile: profile.to_string(),
endpoint: format!("https://{profile}.example.test/openrtb"),
Expand Down
1 change: 1 addition & 0 deletions crates/trusted-server-core/src/auction_config_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@ impl AuctionConfig {
(
id,
ProviderConfig {
allow_insecure_http: false,
protocol: "openrtb-2.6".to_string(),
profile: "standard".to_string(),
endpoint: format!("https://{name}.example/openrtb2/auction"),
Expand Down
1 change: 1 addition & 0 deletions crates/trusted-server-core/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -911,6 +911,7 @@ formats = [{ width = 300, height = 250 }]
settings.auction.providers.insert(
"aps-main".parse().expect("should parse APS provider ID"),
ProviderConfig {
allow_insecure_http: false,
protocol: "openrtb-2.6".to_string(),
profile: "aps".to_string(),
endpoint: "https://aps.example.com/e/pb/bid".to_string(),
Expand Down
1 change: 1 addition & 0 deletions crates/trusted-server-core/src/creative_opportunities.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2383,6 +2383,7 @@ mod tests {
providers: BTreeMap::from([(
ProviderId::from_str("pbs-primary").expect("should parse provider ID"),
ProviderConfig {
allow_insecure_http: false,
protocol: "openrtb-2.6".to_string(),
profile: "prebid-server".to_string(),
endpoint: "https://pbs.example.test/openrtb".to_string(),
Expand Down
2 changes: 2 additions & 0 deletions crates/trusted-server-core/src/integrations/aps.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1939,6 +1939,7 @@ pub fn register(
providers: BTreeMap::from([(
"aps".parse().expect("should parse APS provider ID"),
ProviderConfig {
allow_insecure_http: false,
protocol: "openrtb-2.6".to_string(),
profile: "aps".to_string(),
endpoint: default_endpoint(),
Expand Down Expand Up @@ -3077,6 +3078,7 @@ mod tests {
providers: BTreeMap::from([(
"aps".parse().expect("should parse APS provider ID"),
ProviderConfig {
allow_insecure_http: false,
protocol: "openrtb-2.6".to_string(),
profile: "aps".to_string(),
endpoint: default_endpoint(),
Expand Down
3 changes: 3 additions & 0 deletions crates/trusted-server-core/src/integrations/prebid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5622,6 +5622,7 @@ external_bundle_sri = "sha384-AAAA"
(
ProviderId::from_str("pbs-primary").expect("should parse provider ID"),
ProviderConfig {
allow_insecure_http: false,
protocol: "openrtb-2.6".to_string(),
profile: "prebid-server".to_string(),
endpoint: "https://primary.example.test/openrtb".to_string(),
Expand All @@ -5634,6 +5635,7 @@ external_bundle_sri = "sha384-AAAA"
(
ProviderId::from_str("pbs-secondary").expect("should parse provider ID"),
ProviderConfig {
allow_insecure_http: false,
protocol: "openrtb-2.6".to_string(),
profile: "prebid-server".to_string(),
endpoint: "https://secondary.example.test/openrtb".to_string(),
Expand Down Expand Up @@ -9098,6 +9100,7 @@ set = { networkId = 42 }
providers: BTreeMap::from([(
provider_id.clone(),
ProviderConfig {
allow_insecure_http: false,
protocol: "openrtb-2.6".to_string(),
profile: "prebid-server".to_string(),
endpoint: "https://pbs.example/openrtb2/auction".to_string(),
Expand Down
19 changes: 10 additions & 9 deletions docs/guide/auction-orchestration.md
Original file line number Diff line number Diff line change
Expand Up @@ -773,15 +773,16 @@ registered integration selected by `[auction].mediator`.

Common provider fields and defaults:

| Field | Default | Meaning |
| ---------------- | --------------- | -------------------------------------------------------------- |
| `protocol` | Required | `openrtb-2.6` |
| `profile` | `standard` | Typed OpenRTB behavior |
| `endpoint` | Required | Fixed absolute HTTPS endpoint |
| `timeout_ms` | Profile default | PBS 1000 ms, APS 800 ms, standard inherits auction timeout |
| `routing` | `explicit` | `explicit`, or `all_eligible` for non-PBS profiles |
| `profile_config` | `{}` | Profile-owned typed settings |
| `notifications` | No suppression | Common `nurl`/`burl` suppression by all bids or returned seats |
| Field | Default | Meaning |
| --------------------- | --------------- | ---------------------------------------------------------------------------------- |
| `protocol` | Required | `openrtb-2.6` |
| `profile` | `standard` | Typed OpenRTB behavior |
| `endpoint` | Required | Fixed absolute HTTPS endpoint |

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

⛏ nitpick — The endpoint row still says HTTPS-only, which contradicts the new row below it:

Suggested change
| `endpoint` | Required | Fixed absolute HTTPS endpoint |
| `endpoint` | Required | Fixed absolute HTTPS endpoint; plain HTTP only with `allow_insecure_http` |

| `allow_insecure_http` | `false` | Explicit per-provider HTTP opt-in for approved demos/tests; traffic is unencrypted |
| `timeout_ms` | Profile default | PBS 1000 ms, APS 800 ms, standard inherits auction timeout |
| `routing` | `explicit` | `explicit`, or `all_eligible` for non-PBS profiles |
| `profile_config` | `{}` | Profile-owned typed settings |
| `notifications` | No suppression | Common `nurl`/`burl` suppression by all bids or returned seats |

Comment on lines +780 to 786

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

♻️ refactor: The endpoint row still reads as HTTPS-only, and "traffic is unencrypted" understates what an operator is opting into: client IP, geo, consent and identifiers leave in cleartext, and responses can be altered. A short warning block keeps the table cell readable. The cell widths are sized so prettier leaves the other rows alone.

Suggested change
| `endpoint` | Required | Fixed absolute HTTPS endpoint |
| `allow_insecure_http` | `false` | Explicit per-provider HTTP opt-in for approved demos/tests; traffic is unencrypted |
| `timeout_ms` | Profile default | PBS 1000 ms, APS 800 ms, standard inherits auction timeout |
| `routing` | `explicit` | `explicit`, or `all_eligible` for non-PBS profiles |
| `profile_config` | `{}` | Profile-owned typed settings |
| `notifications` | No suppression | Common `nurl`/`burl` suppression by all bids or returned seats |
| `endpoint` | Required | Fixed absolute HTTPS endpoint; plain HTTP only with `allow_insecure_http` |
| `allow_insecure_http` | `false` | Per-provider plain HTTP opt-in for approved demo/test endpoints; see warning below |
| `timeout_ms` | Profile default | PBS 1000 ms, APS 800 ms, standard inherits auction timeout |
| `routing` | `explicit` | `explicit`, or `all_eligible` for non-PBS profiles |
| `profile_config` | `{}` | Profile-owned typed settings |
| `notifications` | No suppression | Common `nurl`/`burl` suppression by all bids or returned seats |
::: warning Plaintext provider traffic
`allow_insecure_http = true` sends that provider's requests without TLS. Their
headers and OpenRTB bodies, including client IP, User-Agent, geo, consent
signals and identifiers such as the EC ID and EIDs, are readable on the
network, and bid prices, creatives and notification URLs in its responses can
be altered in transit. The flag does not restrict which hosts are reachable.
:::

APS normally uses `all_eligible`, which sends every compatible banner slot but
never another provider's bidder parameters. `explicit` providers receive only
Expand Down
Loading
Loading