From f6c089b8faae015c5b8845296af7cdc3ddcd0c65 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sun, 16 Aug 2026 16:17:48 +0000 Subject: [PATCH 1/9] feat(core): refuse Chrome downloads as Agent download A Chrome downloads permission is compatibility evidence only. Adapters must fail closed before treating it as Capability::Download. Co-authored-by: Seongho Bae --- CHANGELOG.md | 1 + crates/originweave-core/src/lib.rs | 52 +++++++++++++++++++ .../tests/extension_authority.rs | 40 +++++++++++++- .../0013-manifest-v3-extension-authority.md | 2 +- docs/doctoring.md | 6 +++ docs/doctoring/mv3-compatibility.md | 2 +- docs/traceability/README.md | 2 +- .../extension-authority-security.md | 1 + 8 files changed, 101 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6e4bd39c..aac33fc3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ All notable changes to OriginWeave are documented in this file. The format follo ### Added +- Fail-closed `chrome_permission_authorizes_agent_action` boundary so a Chrome `downloads` permission, or any other reviewed Chrome compatibility permission, cannot authorize `Capability::Download` or any other Agent action. - Rust workspace for independently reusable core, policy, destination, network, TLS, resource, and evidence modules. - Canonical HTTPS and loopback-origin boundary with case-normalized schemes and hosts, default-port normalization, IPv4/IPv6 handling, browser-special numeric-host rejection, and explicit malformed-input errors. - Typed browser actions, capabilities, risk classes, execution modes, robots decisions, secret-delivery contracts, immutable canonical action-intent digests, and intent-bound approval scopes. diff --git a/crates/originweave-core/src/lib.rs b/crates/originweave-core/src/lib.rs index 88dd2e58..6afa79b5 100644 --- a/crates/originweave-core/src/lib.rs +++ b/crates/originweave-core/src/lib.rs @@ -1063,3 +1063,55 @@ pub fn evaluate_extension_access( } ExtensionAccessDecision::Allow } + +/// Why a Chrome extension permission cannot authorize an OriginWeave Agent action. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum ChromePermissionAuthorityError { + /// The permission names a reviewed Chrome compatibility surface, not Agent authority. + CompatibilitySurfaceOnly, + /// The permission is not a reviewed Chrome surface and still grants no Agent capability. + UnrecognizedPermission, +} + +const REVIEWED_CHROME_COMPATIBILITY_PERMISSIONS: &[&str] = &[ + "bookmarks", + "declarativeNetRequest", + "declarativeNetRequestWithHostAccess", + "downloads", + "history", + "scripting", + "sidePanel", + "storage", + "tabs", +]; + +/// Refuse to treat a Chrome extension permission as OriginWeave Agent authority. +/// +/// A successful `chrome.downloads` compatibility proof, or any other reviewed +/// Chrome permission, never becomes [`Capability::Download`] or any other Agent +/// capability. Adapters must keep Manifest V3 evidence and Agent grants separate +/// and call this boundary before exposing a typed action to policy. +pub fn chrome_permission_authorizes_agent_action( + permission: &str, + action: ActionKind, +) -> Result<(), ChromePermissionAuthorityError> { + let _action = action; + if !is_exact_chrome_permission_token(permission) { + return Err(ChromePermissionAuthorityError::UnrecognizedPermission); + } + if REVIEWED_CHROME_COMPATIBILITY_PERMISSIONS.contains(&permission) { + return Err(ChromePermissionAuthorityError::CompatibilitySurfaceOnly); + } + Err(ChromePermissionAuthorityError::UnrecognizedPermission) +} + +fn is_exact_chrome_permission_token(permission: &str) -> bool { + let mut characters = permission.chars(); + let Some(first) = characters.next() else { + return false; + }; + first.is_ascii_lowercase() + && permission + .chars() + .all(|character| character.is_ascii_alphabetic()) +} diff --git a/crates/originweave-core/tests/extension_authority.rs b/crates/originweave-core/tests/extension_authority.rs index 82507a24..9002004a 100644 --- a/crates/originweave-core/tests/extension_authority.rs +++ b/crates/originweave-core/tests/extension_authority.rs @@ -1,8 +1,9 @@ #![allow(clippy::expect_used)] use originweave_core::{ - BrowserSessionId, BrowsingContextId, ExtensionAccessDecision, ExtensionAccessRequest, - ExtensionAgentCapability, ExtensionAgentGrant, ExtensionId, evaluate_extension_access, + ActionKind, BrowserSessionId, BrowsingContextId, ChromePermissionAuthorityError, + ExtensionAccessDecision, ExtensionAccessRequest, ExtensionAgentCapability, ExtensionAgentGrant, + ExtensionId, chrome_permission_authorizes_agent_action, evaluate_extension_access, }; fn extension_id(value: &str) -> ExtensionId { @@ -144,3 +145,38 @@ fn explicit_grant_can_authorize_multiple_bounded_agent_capabilities() { ); } } + +#[test] +fn chrome_downloads_permission_cannot_authorize_agent_download() { + assert_eq!( + chrome_permission_authorizes_agent_action("downloads", ActionKind::Download), + Err(ChromePermissionAuthorityError::CompatibilitySurfaceOnly) + ); + assert_eq!( + chrome_permission_authorizes_agent_action("bookmarks", ActionKind::Download), + Err(ChromePermissionAuthorityError::CompatibilitySurfaceOnly) + ); + assert_eq!( + chrome_permission_authorizes_agent_action("history", ActionKind::Download), + Err(ChromePermissionAuthorityError::CompatibilitySurfaceOnly) + ); + assert_eq!( + chrome_permission_authorizes_agent_action("DOWNLOADS", ActionKind::Download), + Err(ChromePermissionAuthorityError::UnrecognizedPermission) + ); + assert_eq!( + chrome_permission_authorizes_agent_action("", ActionKind::Download), + Err(ChromePermissionAuthorityError::UnrecognizedPermission) + ); + assert_eq!( + chrome_permission_authorizes_agent_action( + "downloads\nhttps://example.invalid", + ActionKind::Navigate + ), + Err(ChromePermissionAuthorityError::UnrecognizedPermission) + ); + assert_eq!( + chrome_permission_authorizes_agent_action("cookies", ActionKind::Download), + Err(ChromePermissionAuthorityError::UnrecognizedPermission) + ); +} diff --git a/docs/adr/0013-manifest-v3-extension-authority.md b/docs/adr/0013-manifest-v3-extension-authority.md index e620edf9..c85a7942 100644 --- a/docs/adr/0013-manifest-v3-extension-authority.md +++ b/docs/adr/0013-manifest-v3-extension-authority.md @@ -56,7 +56,7 @@ Selected. 1. **Retain Chromium Manifest V3 as the compatibility plane.** OriginWeave does not create a competing Rust extension API for browser compatibility. 2. **Separate execution modes.** Human Mode may use the person's compatible extension set under browser/enterprise policy. Agent Task Mode defaults to no extensions or an explicit managed allow-list. Later attached-human-tab execution is labelled reduced-assurance when pre-existing extensions can influence page state. 3. **Require explicit OriginWeave extension authority.** Any extension-to-Agent interaction that can affect an Agent Task requires an `extension_grant` or equivalent typed decision bound at minimum to extension identity/version policy, session, applicable browsing context, capability, origin/resource scope, expiry, and task. -4. **Never translate Chrome permission into Agent capability.** `tabs`, `scripting`, `downloads`, `declarativeNetRequest`, host permissions, native messaging, or managed policy do not grant OriginWeave navigation, action, approval, secret, or sensitive-data authority. +4. **Never translate Chrome permission into Agent capability.** `tabs`, `scripting`, `downloads`, `declarativeNetRequest`, host permissions, native messaging, or managed policy do not grant OriginWeave navigation, action, approval, secret, or sensitive-data authority. The reusable `chrome_permission_authorizes_agent_action` primitive is the fail-closed adapter check for that rule. 5. **Keep extension output untrusted.** Extension messages and content enter the bounded observation/provenance path. They cannot alter the trusted goal, add tools, mint capabilities, approve high-risk actions, or weaken deterministic policy. 6. **Keep protected values brokered.** An extension does not receive raw credentials or sensitive values merely because it can inspect or modify a page. Independent secret/sensitive-data authority is rechecked immediately before trusted browser dispatch. 7. **Bound native messaging separately.** Native messaging is supported only behind an explicit host-managed allow-list, exact extension/host identity policy, process boundary, bounded I/O, and auditable lifecycle. It remains unsupported until that executable boundary exists. diff --git a/docs/doctoring.md b/docs/doctoring.md index 75c107ef..8af59c43 100644 --- a/docs/doctoring.md +++ b/docs/doctoring.md @@ -8,6 +8,10 @@ This document records external evidence that changes OriginWeave architecture, t The 1 June 2026 WebDriver BiDi Working Draft defines a bidirectional remote-control protocol, events, commands, and user contexts. Because it remains a W3C Working Draft, OriginWeave places BiDi behind a versioned adapter and Web Platform Tests-derived contract tests rather than make it the internal authority model. +### Chrome extension permission versus Agent capability + +The current Chrome Extensions Downloads API documents the `downloads` manifest permission and `chrome.downloads` methods that initiate, monitor, search, and inspect downloads. That living vendor reference is API semantics for Chromium compatibility only. OriginWeave therefore refuses to convert a Chrome `downloads` permission—or any other reviewed Chrome compatibility permission—into Agent `Download` capability or any other Agent capability. A later pinned-Chromium downloads fixture may prove that the API works; it still cannot mint Agent filesystem or download authority. + ### Browser origin equivalence The WHATWG URL host parser and Chromium canonicalizer classify shortened decimal, integer, hexadecimal, legacy octal-looking, and mixed-component numeric hosts as IPv4 or broken IPv4 candidates rather than ordinary DNS names. Chromium's regression suite includes values such as `192`, `0xC0a80001`, `030052000001`, and mixed hexadecimal components. A non-final empty `0x` component can participate in Chromium's multi-part IPv4 truncation behavior, but a final `0x` label does not produce an IPv4 number because stripping its prefix leaves no digits; it remains a domain label. Chromium also warns that broken IP-like hosts must not be connected because another resolver could accept them. OriginWeave therefore admits only canonical dotted-decimal IPv4 into its policy origin type, rejects browser-special numeric spellings before DNS validation, and preserves final non-numeric DNS labels such as `0x`. @@ -98,6 +102,8 @@ Autio, C., Schwartz, R., Dunietz, J., Jain, S., Stanley, M., Tabassi, E., Hall, Bonica, R., Cotton, M., Haberman, B., & Vegoda, L. (2017). *Updates to the special-purpose IP address registries* (RFC 8190). Internet Engineering Task Force. https://doi.org/10.17487/RFC8190 +Chrome for Developers. (n.d.). *chrome.downloads*. Google. Retrieved August 16, 2026, from https://developer.chrome.com/docs/extensions/reference/api/downloads + Chromium Authors. (n.d.). *Proxy support in Chrome* [Source documentation]. Chromium. https://chromium.googlesource.com/chromium/src/+/a3e71ebfa307d8760eb68b777e2998a869940092/net/docs/proxy.md Chromium Authors. (2026). *URL canonicalizer unit tests* [Source code]. Chromium. https://chromium.googlesource.com/chromium/src/+/446d05d21720f0b3505ec21057b3e9f909784262/url/url_canon_unittest.cc diff --git a/docs/doctoring/mv3-compatibility.md b/docs/doctoring/mv3-compatibility.md index 571c4932..32a561ae 100644 --- a/docs/doctoring/mv3-compatibility.md +++ b/docs/doctoring/mv3-compatibility.md @@ -6,7 +6,7 @@ OriginWeave uses Chromium as its compatibility kernel, so browser-extension compatibility must be demonstrated with executable Chromium evidence rather than inferred from architecture alone. The protected-main lane exercises a controlled unpacked Manifest V3 extension against one exact Chrome for Testing build and proves service-worker, content-script, storage, declarative-network-request, tabs, windows, scripting, commands, side-panel, bookmarks/history read compatibility, restart persistence, repeatability, and one real WebDriver click/post-condition. Active stacked compatibility work adds downloads, bounded bookmark/history mutation, profile isolation, explicit extension update/version-migration evidence, and an exact content-script isolated-world check. OriginWeave does **not claim 100% Chrome extension compatibility**. -The checked-in fixture is intentionally local-only. Its host permission is limited to loopback HTTP used by the deterministic test server. It contains no remote code, user credential, model call, external content, native-messaging host, or production PII. Chrome permissions remain distinct from the explicit OriginWeave extension-to-Agent grant implemented in `originweave-core`. Compatibility mutation tests create only controlled synthetic state inside the ephemeral test profile and must clean it up; successful API compatibility never grants the OriginWeave Agent ambient bookmarks/history/downloads authority. +The checked-in fixture is intentionally local-only. Its host permission is limited to loopback HTTP used by the deterministic test server. It contains no remote code, user credential, model call, external content, native-messaging host, or production PII. Chrome permissions remain distinct from the explicit OriginWeave extension-to-Agent grant implemented in `originweave-core`. `chrome_permission_authorizes_agent_action` refuses Chrome `downloads` and other reviewed compatibility permissions as Agent download or any other Agent action. Compatibility mutation tests create only controlled synthetic state inside the ephemeral test profile and must clean it up; successful API compatibility never grants the OriginWeave Agent ambient bookmarks/history/downloads authority. ## Supported-capability evidence matrix diff --git a/docs/traceability/README.md b/docs/traceability/README.md index e30b9eda..9dde8b8f 100644 --- a/docs/traceability/README.md +++ b/docs/traceability/README.md @@ -70,7 +70,7 @@ ADR lifecycle is separate and remains `Proposed`, `Accepted`, `Superseded`, `Dep | Structured observation precedes raw HTML/screenshot fallback | ACCEPTED_ARCHITECTURE | PRD-OBS-003; TRD Section 7 | Active PR #52 supplies a non-shipped bounded semantic value primitive; real browser observation and fallback adapters remain Planned | | WebDriver BiDi / CDP / WebMCP / MCP are adapters, not internal authority | ACCEPTED_ARCHITECTURE | PRD Section 9.8; TRD Section 12 | Protocol adapter implementation remains Planned/active under issue #28; active PR #40 may not be called shipped | | Manifest V3 compatibility is preserved upstream where practical | PARTIAL | ADR 0001; issue #27; Proposed ADR 0013 | Protected main has pinned real-Chromium compatibility evidence for service worker/content script/storage/DNR/tabs/windows/scripting/commands/side panel/bookmarks/history/restart/repeatability; active PR #43 adds real bounded downloads evidence; full issue #27 matrix remains incomplete | -| Extension permission does not imply OriginWeave Agent capability | PARTIAL | protected-main extension authority kernel; Proposed ADR 0013 | Core extension-to-Agent authority isolation exists on protected main; complete managed-extension/native-messaging/enterprise release policy remains incomplete | +| Extension permission does not imply OriginWeave Agent capability | PARTIAL | protected-main extension authority kernel; Proposed ADR 0013 | Core grant evaluation plus `chrome_permission_authorizes_agent_action` refuse Chrome `downloads` and other reviewed permissions as Agent capability; complete managed-extension/native-messaging/enterprise release policy remains incomplete | | WARC/PROV-oriented durable evidence adapters | PLANNED | ADR 0003; PRD-EVD-005 | Source/provenance kernel foundation exists; persistence/export adapters remain Planned | | Origin Map visualizes value/action provenance | PLANNED | PRD-EVD-004; this traceability record | No shipped UI claim | | Browser / Runtime / Observe / Capture / Governor / Policy / Evidence / Protocol / SDK product surfaces | PARTIAL | PRD Section 6 | Some foundations exist under crates; named commercial surfaces are not all shipped artifacts | diff --git a/docs/traceability/extension-authority-security.md b/docs/traceability/extension-authority-security.md index a36380a3..cd2e5afe 100644 --- a/docs/traceability/extension-authority-security.md +++ b/docs/traceability/extension-authority-security.md @@ -17,6 +17,7 @@ This dossier records the current executable composition evidence for that separa Protected `main` already provides: - exact extension/session/context-scoped `ExtensionAgentGrant` evaluation; +- `chrome_permission_authorizes_agent_action`, which refuses Chrome `downloads` and other reviewed compatibility permissions as Agent `Download` or any other Agent action; - a distinction between `ObserveCurrentContext` and `ProposeTypedAction` extension capabilities; - deterministic Agent policy evaluation for typed actions; - fail-closed treatment of `InstructionSource::WebContent`; From 52e42370ce49ad6142fb19eb0211f43716f19803 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Mon, 17 Aug 2026 05:05:15 +0900 Subject: [PATCH 2/9] docs(traceability): keep Chrome permission guard active-PR only --- .../extension-authority-security.md | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/docs/traceability/extension-authority-security.md b/docs/traceability/extension-authority-security.md index cd2e5afe..e7e9e559 100644 --- a/docs/traceability/extension-authority-security.md +++ b/docs/traceability/extension-authority-security.md @@ -2,7 +2,7 @@ - **Documentation status:** Active-PR evidence dossier - **Canonical owner:** PR #44 (`docs: reconcile architecture documentation fitness`) -- **Protected-main baseline:** `67af7c87589edc2039545af335c95064d9b8391c` +- **Protected-main baseline:** `0c376acf059be9ddddddfbde1d0189e4f39ef014` - **Capability maturity:** **PARTIAL** - **Governing decision:** Proposed ADR 0013 separates Manifest V3 compatibility from OriginWeave Agent authority. @@ -17,7 +17,6 @@ This dossier records the current executable composition evidence for that separa Protected `main` already provides: - exact extension/session/context-scoped `ExtensionAgentGrant` evaluation; -- `chrome_permission_authorizes_agent_action`, which refuses Chrome `downloads` and other reviewed compatibility permissions as Agent `Download` or any other Agent action; - a distinction between `ObserveCurrentContext` and `ProposeTypedAction` extension capabilities; - deterministic Agent policy evaluation for typed actions; - fail-closed treatment of `InstructionSource::WebContent`; @@ -29,15 +28,23 @@ These foundations are **IMPLEMENTED_ON_PROTECTED_MAIN**. They do not by themselv ## 3. Active executable evidence +### PR #175 — Chrome permission cannot mint Agent action authority + +**Capability maturity:** `IMPLEMENTED_ON_ACTIVE_PR` + +Exact head `f6c089b8faae015c5b8845296af7cdc3ddcd0c65` adds the fail-closed `chrome_permission_authorizes_agent_action` boundary. Reviewed Chrome compatibility permissions such as `downloads`, `bookmarks`, `history`, `storage`, `tabs`, `scripting`, `sidePanel`, `declarativeNetRequest`, and `declarativeNetRequestWithHostAccess` are classified as compatibility surfaces only; malformed, case-shifted, or unrecognized tokens remain unrecognized. The function never returns successful Agent authorization, so Manifest V3 compatibility evidence cannot mint `Capability::Download` or another Agent action. + +This is active-PR evidence only. Until PR #175 integrates into protected `main`, the function must not be listed as a protected-main capability. + ### PR #62 — proposal authority cannot widen Agent, instruction, or secret-material authority **Capability maturity:** `IMPLEMENTED_ON_ACTIVE_PR` -Exact head `a57873b3688984711918be17aadd348ed9fb12a9` proves that, after an extension is genuinely allowed to `ProposeTypedAction`: +Exact head `e7265a86d63c9e5f047ed6d32c3988b01e53fa13` proves that, after an extension is genuinely allowed to `ProposeTypedAction`: 1. a proposed navigation outside the Agent readable-origin grant is still denied; 2. proposal permission cannot supply the missing Agent `Navigate` capability; -3. extension-produced untrusted content remains rejected as instruction authority; +3. extension-produced `WebContent` cannot become a trusted policy instruction; 4. `FillSecret` with `SecretDelivery::RawValue` remains denied as `SecretBrokerRequired`; and 5. secret material attached to a non-secret action remains denied as `UnexpectedSecretMaterial`. @@ -47,9 +54,9 @@ The branch adds no production API and no extension runtime. It is compositional **Capability maturity:** `IMPLEMENTED_ON_ACTIVE_PR` -Exact head `e83749acd1cf5a0b778ba38eb9d6ed5a9bd1e68f` deliberately keeps only the distinct approval-composition proof after duplicate regressions were removed in favor of PR #62 ownership. It proves that, after the same exact proposal grant is admitted and the Agent context independently possesses `FillSecret` plus exact readable/writable origin authority, broker-handle `FillSecret` still reaches the ordinary R3 approval boundary rather than becoming implicitly allowed. +Exact head `a4595c393f459f57bfe2199ace44271f246751c4` deliberately keeps only the distinct approval-composition proof after duplicate regressions were removed in favor of PR #62 ownership. It proves that, after the same exact proposal grant is admitted and the Agent context independently possesses `FillSecret` plus exact readable/writable origin authority, broker-handle `FillSecret` still reaches the ordinary R3 approval boundary rather than becoming implicitly allowed. -The exact head has successful CI, exact owned production coverage, Security Scan, SAST and CodeRabbit status and is Ready for review. It has no raw secret bytes and does not create approval evidence, a broker, browser-fill adapter, protected-value store, KMS path, authenticated workload identity, persistence owner, or release claim. +The exact head has successful CI, exact owned production coverage, Security Scan, and SAST evidence and is Ready for review. It has no raw secret bytes and does not create approval evidence, a broker, browser-fill adapter, protected-value store, KMS path, authenticated workload identity, persistence owner, or release claim. ## 4. Security interpretation @@ -83,4 +90,4 @@ This dossier does **not** close issue #27 or issue #10. Remaining material work ## 6. Documentation fitness consequence -The existing ADR/PRD/TRD/Architecture/UML/ERD graph remains **DESIGN-SUFFICIENT / PROTECTED-MAIN-PARTIAL**. PRs #62 and #63 narrow distinct executable extension-authority evidence gaps without introducing a new trust domain, deployment component, persistence entity, database schema, or independent architecture decision. Proposed ADR 0013 remains Proposed until its own lifecycle authority changes. \ No newline at end of file +The existing ADR/PRD/TRD/Architecture/UML/ERD graph remains **DESIGN-SUFFICIENT / PROTECTED-MAIN-PARTIAL**. PRs #62, #63, and #175 narrow distinct executable extension-authority evidence gaps without introducing a new trust domain, deployment component, persistence entity, database schema, or independent architecture decision. Proposed ADR 0013 remains Proposed until its own lifecycle authority changes. From a295616e1ae743e474e58deb067a303c17605fa3 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Mon, 17 Aug 2026 07:43:39 +0900 Subject: [PATCH 3/9] test(core): isolate Chrome permission imports for main convergence --- crates/originweave-core/tests/extension_authority.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/crates/originweave-core/tests/extension_authority.rs b/crates/originweave-core/tests/extension_authority.rs index 9002004a..457a5ac2 100644 --- a/crates/originweave-core/tests/extension_authority.rs +++ b/crates/originweave-core/tests/extension_authority.rs @@ -1,9 +1,11 @@ #![allow(clippy::expect_used)] use originweave_core::{ - ActionKind, BrowserSessionId, BrowsingContextId, ChromePermissionAuthorityError, - ExtensionAccessDecision, ExtensionAccessRequest, ExtensionAgentCapability, ExtensionAgentGrant, - ExtensionId, chrome_permission_authorizes_agent_action, evaluate_extension_access, + BrowserSessionId, BrowsingContextId, ExtensionAccessDecision, ExtensionAccessRequest, + ExtensionAgentCapability, ExtensionAgentGrant, ExtensionId, evaluate_extension_access, +}; +use originweave_core::{ + ActionKind, ChromePermissionAuthorityError, chrome_permission_authorizes_agent_action, }; fn extension_id(value: &str) -> ExtensionId { From 681898287df4d503ccf841cd2c2b654b4606008f Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Mon, 17 Aug 2026 07:44:19 +0900 Subject: [PATCH 4/9] docs(adr): preserve current-main extension authority decision --- docs/adr/0013-manifest-v3-extension-authority.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/adr/0013-manifest-v3-extension-authority.md b/docs/adr/0013-manifest-v3-extension-authority.md index c85a7942..8feacbf2 100644 --- a/docs/adr/0013-manifest-v3-extension-authority.md +++ b/docs/adr/0013-manifest-v3-extension-authority.md @@ -56,7 +56,7 @@ Selected. 1. **Retain Chromium Manifest V3 as the compatibility plane.** OriginWeave does not create a competing Rust extension API for browser compatibility. 2. **Separate execution modes.** Human Mode may use the person's compatible extension set under browser/enterprise policy. Agent Task Mode defaults to no extensions or an explicit managed allow-list. Later attached-human-tab execution is labelled reduced-assurance when pre-existing extensions can influence page state. 3. **Require explicit OriginWeave extension authority.** Any extension-to-Agent interaction that can affect an Agent Task requires an `extension_grant` or equivalent typed decision bound at minimum to extension identity/version policy, session, applicable browsing context, capability, origin/resource scope, expiry, and task. -4. **Never translate Chrome permission into Agent capability.** `tabs`, `scripting`, `downloads`, `declarativeNetRequest`, host permissions, native messaging, or managed policy do not grant OriginWeave navigation, action, approval, secret, or sensitive-data authority. The reusable `chrome_permission_authorizes_agent_action` primitive is the fail-closed adapter check for that rule. +4. **Never translate Chrome permission into Agent capability.** `tabs`, `scripting`, `downloads`, `declarativeNetRequest`, host permissions, native messaging, or managed policy do not grant OriginWeave navigation, action, approval, secret, or sensitive-data authority. 5. **Keep extension output untrusted.** Extension messages and content enter the bounded observation/provenance path. They cannot alter the trusted goal, add tools, mint capabilities, approve high-risk actions, or weaken deterministic policy. 6. **Keep protected values brokered.** An extension does not receive raw credentials or sensitive values merely because it can inspect or modify a page. Independent secret/sensitive-data authority is rechecked immediately before trusted browser dispatch. 7. **Bound native messaging separately.** Native messaging is supported only behind an explicit host-managed allow-list, exact extension/host identity policy, process boundary, bounded I/O, and auditable lifecycle. It remains unsupported until that executable boundary exists. @@ -92,7 +92,7 @@ No persistent database migration is introduced. A release can roll back the Chro ## Open follow-ups -- Complete issue #27's compatibility matrix and production isolation acceptance. +- Complete issue #27's compatibility matrix and production isolation acceptance. Exclusive trusted-time expiry on origin-bound `ExtensionAgentGrant` evaluation is the next protected-main candidate; task identity binding remains open. - Define managed-extension identity/update semantics. - Implement the native-messaging allow-list/process boundary before claiming support. - Integrate the complete Agent Task browser vertical slice under issue #28. From 1cff725097f11153bdabff0dfbd6dc8860954a87 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Mon, 17 Aug 2026 07:45:03 +0900 Subject: [PATCH 5/9] chore(core): preserve current-main authority docs while converging Chrome permission guard --- CHANGELOG.md | 3 ++- docs/doctoring.md | 18 ++++++++----- .../extension-authority-security.md | 26 +++++++++---------- 3 files changed, 26 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index aac33fc3..d1741992 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,8 @@ All notable changes to OriginWeave are documented in this file. The format follo ### Added -- Fail-closed `chrome_permission_authorizes_agent_action` boundary so a Chrome `downloads` permission, or any other reviewed Chrome compatibility permission, cannot authorize `Capability::Download` or any other Agent action. +- Bound explicit extension-to-Agent grants to exclusive trusted-time expiry in addition to extension identity, session, browsing context, and canonical origin, so a same-origin grant cannot be reused at or after the deadline. +- Bound explicit extension-to-Agent grants to the exact canonical origin in addition to extension identity, session, and browsing context, so a same-session navigation or port change cannot reuse the grant. - Rust workspace for independently reusable core, policy, destination, network, TLS, resource, and evidence modules. - Canonical HTTPS and loopback-origin boundary with case-normalized schemes and hosts, default-port normalization, IPv4/IPv6 handling, browser-special numeric-host rejection, and explicit malformed-input errors. - Typed browser actions, capabilities, risk classes, execution modes, robots decisions, secret-delivery contracts, immutable canonical action-intent digests, and intent-bound approval scopes. diff --git a/docs/doctoring.md b/docs/doctoring.md index 8af59c43..f0133bb5 100644 --- a/docs/doctoring.md +++ b/docs/doctoring.md @@ -8,16 +8,20 @@ This document records external evidence that changes OriginWeave architecture, t The 1 June 2026 WebDriver BiDi Working Draft defines a bidirectional remote-control protocol, events, commands, and user contexts. Because it remains a W3C Working Draft, OriginWeave places BiDi behind a versioned adapter and Web Platform Tests-derived contract tests rather than make it the internal authority model. -### Chrome extension permission versus Agent capability - -The current Chrome Extensions Downloads API documents the `downloads` manifest permission and `chrome.downloads` methods that initiate, monitor, search, and inspect downloads. That living vendor reference is API semantics for Chromium compatibility only. OriginWeave therefore refuses to convert a Chrome `downloads` permission—or any other reviewed Chrome compatibility permission—into Agent `Download` capability or any other Agent capability. A later pinned-Chromium downloads fixture may prove that the API works; it still cannot mint Agent filesystem or download authority. - ### Browser origin equivalence The WHATWG URL host parser and Chromium canonicalizer classify shortened decimal, integer, hexadecimal, legacy octal-looking, and mixed-component numeric hosts as IPv4 or broken IPv4 candidates rather than ordinary DNS names. Chromium's regression suite includes values such as `192`, `0xC0a80001`, `030052000001`, and mixed hexadecimal components. A non-final empty `0x` component can participate in Chromium's multi-part IPv4 truncation behavior, but a final `0x` label does not produce an IPv4 number because stripping its prefix leaves no digits; it remains a domain label. Chromium also warns that broken IP-like hosts must not be connected because another resolver could accept them. OriginWeave therefore admits only canonical dotted-decimal IPv4 into its policy origin type, rejects browser-special numeric spellings before DNS validation, and preserves final non-numeric DNS labels such as `0x`. The exact Chromium regression evidence is pinned to revision `446d05d21720f0b3505ec21057b3e9f909784262`. A mutable `HEAD` reference is not sufficient for a reproducible security contract. +### Extension-to-Agent grant origin binding + +RFC 6454 defines a web origin as the scheme, host, and port tuple that browsers use to isolate authority. An OriginWeave `extension_grant` that is bound only to extension identity, session, and browsing context would remain valid after the same context navigates to another origin. OriginWeave therefore requires the grant and the request to carry the same canonical origin. A host change or a non-default port change is a different origin and cannot reuse the grant. This is grant-scope isolation only; it does not install an extension, parse Chrome messages, or mint Agent capabilities from Manifest V3 permissions. + +### Extension-to-Agent grant exclusive expiry + +RFC 9700 is the current Best Current Practice for OAuth 2.0 security. It requires access tokens to be restricted in lifetime and treats long-lived bearer credentials as a standing authorization risk. An OriginWeave `extension_grant` that matches extension identity, session, browsing context, and canonical origin but has no exclusive expiry remains usable after the Agent Task window ends. OriginWeave therefore requires the grant to carry an exclusive `expires_at_epoch_seconds` deadline and the request to carry trusted `now_epoch_seconds`. Evaluation fails closed when `now >= expires_at`, matching the existing sensitive-handle exclusive-expiry rule. Page, extension, and model clocks are not trusted time. This slice does not bind task identity, install an extension, or mint Agent capabilities from Manifest V3 permissions. + ### Resolved destination and redirect safety Canonical origin identity is not a network-destination authorization. The IANA IPv4 and IPv6 Special-Purpose Address Space registries enumerate blocks whose source, destination, forwardability, globally reachable, and protocol-reserved properties differ. Both registries were last updated on 9 October 2025 and explicitly warn that registry presence does not guarantee routability in a particular local or global context. RFC 6890 established the common special-purpose registry fields, and RFC 8190 replaced the ambiguous `global` field with `globally reachable`. @@ -100,9 +104,9 @@ Amazon Web Services. (n.d.). *Set up the Amazon EKS Pod Identity Agent*. Retriev Autio, C., Schwartz, R., Dunietz, J., Jain, S., Stanley, M., Tabassi, E., Hall, P., & Roberts, K. (2024). *Artificial intelligence risk management framework: Generative artificial intelligence profile* (NIST AI 600-1). National Institute of Standards and Technology. https://doi.org/10.6028/NIST.AI.600-1 -Bonica, R., Cotton, M., Haberman, B., & Vegoda, L. (2017). *Updates to the special-purpose IP address registries* (RFC 8190). Internet Engineering Task Force. https://doi.org/10.17487/RFC8190 +Barth, A. (2011). *The web origin concept* (RFC 6454). Internet Engineering Task Force. https://doi.org/10.17487/RFC6454 -Chrome for Developers. (n.d.). *chrome.downloads*. Google. Retrieved August 16, 2026, from https://developer.chrome.com/docs/extensions/reference/api/downloads +Bonica, R., Cotton, M., Haberman, B., & Vegoda, L. (2017). *Updates to the special-purpose IP address registries* (RFC 8190). Internet Engineering Task Force. https://doi.org/10.17487/RFC8190 Chromium Authors. (n.d.). *Proxy support in Chrome* [Source documentation]. Chromium. https://chromium.googlesource.com/chromium/src/+/a3e71ebfa307d8760eb68b777e2998a869940092/net/docs/proxy.md @@ -134,6 +138,8 @@ International Organization for Standardization. (2017). *Information and documen Koster, M., Illyes, G., Zeller, H., & Sassman, L. (2022). *Robots Exclusion Protocol* (RFC 9309). Internet Engineering Task Force. https://doi.org/10.17487/RFC9309 +Lodderstedt, T., Bradley, J., Labunets, A., & Fett, D. (2025). *OAuth 2.0 security best current practice* (RFC 9700). Internet Engineering Task Force. https://doi.org/10.17487/RFC9700 + Microsoft. (2025, July 25). *Azure IP address 168.63.129.16 overview*. Microsoft Learn. https://learn.microsoft.com/azure/virtual-network/what-is-ip-address-168-63-129-16 Nielsen, S., Cetin, E., Schwendeman, P., Sun, Q., Xu, J., & Tang, Y. (2025). *Learning to orchestrate agents in natural language with the Conductor* [Preprint]. arXiv. https://doi.org/10.48550/arXiv.2512.04388 diff --git a/docs/traceability/extension-authority-security.md b/docs/traceability/extension-authority-security.md index e7e9e559..1c211f83 100644 --- a/docs/traceability/extension-authority-security.md +++ b/docs/traceability/extension-authority-security.md @@ -2,7 +2,7 @@ - **Documentation status:** Active-PR evidence dossier - **Canonical owner:** PR #44 (`docs: reconcile architecture documentation fitness`) -- **Protected-main baseline:** `0c376acf059be9ddddddfbde1d0189e4f39ef014` +- **Protected-main baseline:** `67af7c87589edc2039545af335c95064d9b8391c` - **Capability maturity:** **PARTIAL** - **Governing decision:** Proposed ADR 0013 separates Manifest V3 compatibility from OriginWeave Agent authority. @@ -28,23 +28,15 @@ These foundations are **IMPLEMENTED_ON_PROTECTED_MAIN**. They do not by themselv ## 3. Active executable evidence -### PR #175 — Chrome permission cannot mint Agent action authority - -**Capability maturity:** `IMPLEMENTED_ON_ACTIVE_PR` - -Exact head `f6c089b8faae015c5b8845296af7cdc3ddcd0c65` adds the fail-closed `chrome_permission_authorizes_agent_action` boundary. Reviewed Chrome compatibility permissions such as `downloads`, `bookmarks`, `history`, `storage`, `tabs`, `scripting`, `sidePanel`, `declarativeNetRequest`, and `declarativeNetRequestWithHostAccess` are classified as compatibility surfaces only; malformed, case-shifted, or unrecognized tokens remain unrecognized. The function never returns successful Agent authorization, so Manifest V3 compatibility evidence cannot mint `Capability::Download` or another Agent action. - -This is active-PR evidence only. Until PR #175 integrates into protected `main`, the function must not be listed as a protected-main capability. - ### PR #62 — proposal authority cannot widen Agent, instruction, or secret-material authority **Capability maturity:** `IMPLEMENTED_ON_ACTIVE_PR` -Exact head `e7265a86d63c9e5f047ed6d32c3988b01e53fa13` proves that, after an extension is genuinely allowed to `ProposeTypedAction`: +Exact head `a57873b3688984711918be17aadd348ed9fb12a9` proves that, after an extension is genuinely allowed to `ProposeTypedAction`: 1. a proposed navigation outside the Agent readable-origin grant is still denied; 2. proposal permission cannot supply the missing Agent `Navigate` capability; -3. extension-produced `WebContent` cannot become a trusted policy instruction; +3. extension-produced untrusted content remains rejected as instruction authority; 4. `FillSecret` with `SecretDelivery::RawValue` remains denied as `SecretBrokerRequired`; and 5. secret material attached to a non-secret action remains denied as `UnexpectedSecretMaterial`. @@ -54,9 +46,15 @@ The branch adds no production API and no extension runtime. It is compositional **Capability maturity:** `IMPLEMENTED_ON_ACTIVE_PR` -Exact head `a4595c393f459f57bfe2199ace44271f246751c4` deliberately keeps only the distinct approval-composition proof after duplicate regressions were removed in favor of PR #62 ownership. It proves that, after the same exact proposal grant is admitted and the Agent context independently possesses `FillSecret` plus exact readable/writable origin authority, broker-handle `FillSecret` still reaches the ordinary R3 approval boundary rather than becoming implicitly allowed. +Exact head `e83749acd1cf5a0b778ba38eb9d6ed5a9bd1e68f` deliberately keeps only the distinct approval-composition proof after duplicate regressions were removed in favor of PR #62 ownership. It proves that, after the same exact proposal grant is admitted and the Agent context independently possesses `FillSecret` plus exact readable/writable origin authority, broker-handle `FillSecret` still reaches the ordinary R3 approval boundary rather than becoming implicitly allowed. + +The exact head has successful CI, exact owned production coverage, Security Scan, SAST and CodeRabbit status and is Ready for review. It has no raw secret bytes and does not create approval evidence, a broker, browser-fill adapter, protected-value store, KMS path, authenticated workload identity, persistence owner, or release claim. + +### Origin-bound extension grant evaluation + +**Capability maturity:** `IMPLEMENTED_ON_ACTIVE_PR` -The exact head has successful CI, exact owned production coverage, Security Scan, and SAST evidence and is Ready for review. It has no raw secret bytes and does not create approval evidence, a broker, browser-fill adapter, protected-value store, KMS path, authenticated workload identity, persistence owner, or release claim. +The current origin-binding slice requires `ExtensionAgentGrant` and `ExtensionAccessRequest` to carry the same canonical origin. A same-session, same-context request for `https://other.example` or `https://app.example:8443` against a grant for `https://app.example` is `DenyOriginMismatch`. Exclusive trusted-time expiry is evaluated after that origin match: `now >= expires_at` is `DenyExpired`. This does not install an extension, parse Chrome messages, bind task identity, or mint Agent capabilities from Manifest V3 permissions. ## 4. Security interpretation @@ -90,4 +88,4 @@ This dossier does **not** close issue #27 or issue #10. Remaining material work ## 6. Documentation fitness consequence -The existing ADR/PRD/TRD/Architecture/UML/ERD graph remains **DESIGN-SUFFICIENT / PROTECTED-MAIN-PARTIAL**. PRs #62, #63, and #175 narrow distinct executable extension-authority evidence gaps without introducing a new trust domain, deployment component, persistence entity, database schema, or independent architecture decision. Proposed ADR 0013 remains Proposed until its own lifecycle authority changes. +The existing ADR/PRD/TRD/Architecture/UML/ERD graph remains **DESIGN-SUFFICIENT / PROTECTED-MAIN-PARTIAL**. PRs #62 and #63 narrow distinct executable extension-authority evidence gaps without introducing a new trust domain, deployment component, persistence entity, database schema, or independent architecture decision. Proposed ADR 0013 remains Proposed until its own lifecycle authority changes. \ No newline at end of file From a144c30df7eb88c3b83fe18ac68c760a839b79bb Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Mon, 17 Aug 2026 11:06:15 +0900 Subject: [PATCH 6/9] feat(core): refuse Chrome permission as Agent authority --- crates/originweave-core/Cargo.toml | 3 ++ .../src/chrome_permission_authority.rs | 53 +++++++++++++++++++ crates/originweave-core/src/crate_root.rs | 17 ++++++ 3 files changed, 73 insertions(+) create mode 100644 crates/originweave-core/src/chrome_permission_authority.rs create mode 100644 crates/originweave-core/src/crate_root.rs diff --git a/crates/originweave-core/Cargo.toml b/crates/originweave-core/Cargo.toml index 35c83b19..15bd2316 100644 --- a/crates/originweave-core/Cargo.toml +++ b/crates/originweave-core/Cargo.toml @@ -10,6 +10,9 @@ repository.workspace = true homepage.workspace = true publish = false +[lib] +path = "src/crate_root.rs" + [dependencies] [lints] diff --git a/crates/originweave-core/src/chrome_permission_authority.rs b/crates/originweave-core/src/chrome_permission_authority.rs new file mode 100644 index 00000000..53e868fb --- /dev/null +++ b/crates/originweave-core/src/chrome_permission_authority.rs @@ -0,0 +1,53 @@ +//! Separation between Chrome extension compatibility permissions and Agent authority. + +use crate::ActionKind; + +/// Why a Chrome extension permission cannot authorize an OriginWeave Agent action. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum ChromePermissionAuthorityError { + /// The permission names a reviewed Chrome compatibility surface, not Agent authority. + CompatibilitySurfaceOnly, + /// The permission is not a reviewed Chrome surface and still grants no Agent capability. + UnrecognizedPermission, +} + +const REVIEWED_CHROME_COMPATIBILITY_PERMISSIONS: &[&str] = &[ + "bookmarks", + "declarativeNetRequest", + "declarativeNetRequestWithHostAccess", + "downloads", + "history", + "scripting", + "sidePanel", + "storage", + "tabs", +]; + +/// Refuse to treat a Chrome extension permission as OriginWeave Agent authority. +/// +/// A successful Chrome compatibility proof never becomes an OriginWeave Agent +/// capability. Adapters must keep browser compatibility evidence and explicit +/// OriginWeave grants separate and call this boundary before exposing a typed +/// action to policy. The action is accepted only to make that separation +/// explicit at the adapter boundary; no action kind can make this function +/// return success. +pub fn chrome_permission_authorizes_agent_action( + permission: &str, + _action: ActionKind, +) -> Result<(), ChromePermissionAuthorityError> { + if !is_exact_chrome_permission_token(permission) { + return Err(ChromePermissionAuthorityError::UnrecognizedPermission); + } + if REVIEWED_CHROME_COMPATIBILITY_PERMISSIONS.contains(&permission) { + return Err(ChromePermissionAuthorityError::CompatibilitySurfaceOnly); + } + Err(ChromePermissionAuthorityError::UnrecognizedPermission) +} + +fn is_exact_chrome_permission_token(permission: &str) -> bool { + let mut characters = permission.chars(); + let Some(first) = characters.next() else { + return false; + }; + first.is_ascii_lowercase() && characters.all(|character| character.is_ascii_alphabetic()) +} diff --git a/crates/originweave-core/src/crate_root.rs b/crates/originweave-core/src/crate_root.rs new file mode 100644 index 00000000..399e21e5 --- /dev/null +++ b/crates/originweave-core/src/crate_root.rs @@ -0,0 +1,17 @@ +//! OriginWeave core contracts plus narrowly scoped adapter authority boundaries. +//! +//! The existing deterministic core remains implemented in `lib.rs`; this crate +//! root re-exports that protected-main API and adds the independently reviewed +//! Chrome-permission separation boundary without weakening existing authority. + +#![forbid(unsafe_code)] +#![deny(missing_docs)] + +#[path = "lib.rs"] +mod base; +pub use base::*; + +mod chrome_permission_authority; +pub use chrome_permission_authority::{ + ChromePermissionAuthorityError, chrome_permission_authorizes_agent_action, +}; From db724d4ec2ecda58f48463546e135d29ba03bd81 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Mon, 17 Aug 2026 11:09:35 +0900 Subject: [PATCH 7/9] docs(changelog): record Chrome permission authority separation --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d1741992..2a62dd8a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ All notable changes to OriginWeave are documented in this file. The format follo ### Added +- Added a fail-closed Chrome-permission separation boundary so reviewed Manifest V3 compatibility permissions, including `downloads`, can never mint any OriginWeave Agent action authority. - Bound explicit extension-to-Agent grants to exclusive trusted-time expiry in addition to extension identity, session, browsing context, and canonical origin, so a same-origin grant cannot be reused at or after the deadline. - Bound explicit extension-to-Agent grants to the exact canonical origin in addition to extension identity, session, and browsing context, so a same-session navigation or port change cannot reuse the grant. - Rust workspace for independently reusable core, policy, destination, network, TLS, resource, and evidence modules. From 4b36b53f6be66bafd5c43e7bc62b2cbd97460ccb Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Mon, 17 Aug 2026 12:32:44 +0900 Subject: [PATCH 8/9] test(core): classify commands and windows as compatibility only --- crates/originweave-core/tests/chrome_permission_authority.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crates/originweave-core/tests/chrome_permission_authority.rs b/crates/originweave-core/tests/chrome_permission_authority.rs index fb5ad2dd..4270f275 100644 --- a/crates/originweave-core/tests/chrome_permission_authority.rs +++ b/crates/originweave-core/tests/chrome_permission_authority.rs @@ -10,7 +10,9 @@ fn chrome_compatibility_permissions_never_mint_agent_authority() { "history", "storage", "tabs", + "windows", "scripting", + "commands", "sidePanel", "declarativeNetRequest", "declarativeNetRequestWithHostAccess", From 6b7cfd74486932541bfedc66c5751a98804a0678 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Mon, 17 Aug 2026 12:34:02 +0900 Subject: [PATCH 9/9] fix(core): classify commands and windows as compatibility only --- crates/originweave-core/src/chrome_permission_authority.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crates/originweave-core/src/chrome_permission_authority.rs b/crates/originweave-core/src/chrome_permission_authority.rs index 53e868fb..68e52661 100644 --- a/crates/originweave-core/src/chrome_permission_authority.rs +++ b/crates/originweave-core/src/chrome_permission_authority.rs @@ -13,6 +13,7 @@ pub enum ChromePermissionAuthorityError { const REVIEWED_CHROME_COMPATIBILITY_PERMISSIONS: &[&str] = &[ "bookmarks", + "commands", "declarativeNetRequest", "declarativeNetRequestWithHostAccess", "downloads", @@ -21,6 +22,7 @@ const REVIEWED_CHROME_COMPATIBILITY_PERMISSIONS: &[&str] = &[ "sidePanel", "storage", "tabs", + "windows", ]; /// Refuse to treat a Chrome extension permission as OriginWeave Agent authority.