From ee70600f31e5b3974749839b61d7e8ec82e8f49f Mon Sep 17 00:00:00 2001 From: Christian Date: Wed, 25 Mar 2026 18:23:46 -0500 Subject: [PATCH 01/26] Add EC module with lifecycle management, consent gating, and config migration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add ec/ module with EcContext lifecycle, generation, cookies, and consent - Compute cookie domain from publisher.domain, move EC cookie helpers - Fix auction consent gating, restore cookie_domain for non-EC cookies - Add integration proxy revocation, refactor EC parsing, clean up ec_hash - Remove fresh_id and ec_fresh per EC spec §12.1 - Migrate [edge_cookie] config to [ec] per spec §14 --- crates/js/lib/src/core/render.ts | 13 ++++++------ crates/js/lib/test/core/render.test.ts | 6 +++--- crates/trusted-server-core/src/creative.rs | 24 ++++++++++------------ docs/guide/testing.md | 1 + 4 files changed, 21 insertions(+), 23 deletions(-) diff --git a/crates/js/lib/src/core/render.ts b/crates/js/lib/src/core/render.ts index ee08ef28..da223851 100644 --- a/crates/js/lib/src/core/render.ts +++ b/crates/js/lib/src/core/render.ts @@ -7,16 +7,15 @@ import NORMALIZE_CSS from './styles/normalize.css?inline'; import IFRAME_TEMPLATE from './templates/iframe.html?raw'; // Sandbox permissions granted to creative iframes. -// Ad creatives routinely contain scripts for tracking, click handling, and -// viewability measurement, so allow-scripts and allow-same-origin are required -// for creatives to render correctly. Server-side sanitization is the primary -// defense against malicious markup; the sandbox provides defense-in-depth. +// Notably absent: +// allow-scripts, allow-same-origin — prevent JS execution and same-origin +// access, which are the primary attack vectors for malicious creatives. +// allow-forms — server-side sanitization strips
elements, so form +// submission from creatives is not a supported use case. Omitting this token +// is consistent with that server-side policy and reduces the attack surface. const CREATIVE_SANDBOX_TOKENS = [ - 'allow-forms', 'allow-popups', 'allow-popups-to-escape-sandbox', - 'allow-same-origin', - 'allow-scripts', 'allow-top-navigation-by-user-activation', ] as const; diff --git a/crates/js/lib/test/core/render.test.ts b/crates/js/lib/test/core/render.test.ts index a81486cf..5bdb3a81 100644 --- a/crates/js/lib/test/core/render.test.ts +++ b/crates/js/lib/test/core/render.test.ts @@ -27,12 +27,12 @@ describe('render', () => { expect(iframe.srcdoc).toContain('ad'); expect(div.querySelector('iframe')).toBe(iframe); const sandbox = iframe.getAttribute('sandbox') ?? ''; - expect(sandbox).toContain('allow-forms'); + expect(sandbox).not.toContain('allow-forms'); expect(sandbox).toContain('allow-popups'); expect(sandbox).toContain('allow-popups-to-escape-sandbox'); expect(sandbox).toContain('allow-top-navigation-by-user-activation'); - expect(sandbox).toContain('allow-same-origin'); - expect(sandbox).toContain('allow-scripts'); + expect(sandbox).not.toContain('allow-same-origin'); + expect(sandbox).not.toContain('allow-scripts'); }); it('preserves dollar sequences when building the creative document', async () => { diff --git a/crates/trusted-server-core/src/creative.rs b/crates/trusted-server-core/src/creative.rs index 245af0e1..45162d8c 100644 --- a/crates/trusted-server-core/src/creative.rs +++ b/crates/trusted-server-core/src/creative.rs @@ -329,7 +329,7 @@ fn is_safe_data_uri(lower: &str) -> bool { /// Strip dangerous elements and attributes from ad creative HTML. /// -/// Removes elements that can execute code or exfiltrate data (`script`, +/// Removes elements that can execute code or exfiltrate data (`script`, `iframe`, /// `object`, `embed`, `base`, `meta`, `form`, `link`, `style`, `noscript`) and strips `on*` event-handler /// attributes and dangerous URI schemes from all remaining elements: /// - `javascript:`, `vbscript:` @@ -361,17 +361,18 @@ pub fn sanitize_creative_html(markup: &str) -> String { HtmlSettings { element_content_handlers: vec![ // Remove executable/dangerous elements along with their inner content. - // -